diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 7ec70a9cca..8160d1c8db 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -37,13 +37,10 @@ #include #include #include -#include -#include -#include #include "Application.h" #include "InterfaceConfig.h" -#include "Log.h" +#include "LogDisplay.h" #include "OculusManager.h" #include "Util.h" #include "renderer/ProgramObject.h" @@ -161,10 +158,6 @@ Application::Application(int& argc, char** argv) : _voxels.setViewFrustum(&_viewFrustum); - shared_lib::printLog = & ::printLog; - voxels_lib::printLog = & ::printLog; - avatars_lib::printLog = & ::printLog; - unsigned int listenPort = AGENT_SOCKET_LISTEN_PORT; const char** constArgv = const_cast(argv); const char* portStr = getCmdOption(argc, constArgv, "--listenPort"); @@ -1774,7 +1767,7 @@ void Application::displayOverlay() { glPointSize(1.0f); if (_renderStatsOn->isChecked()) { displayStats(); } - if (_logOn->isChecked()) { logger.render(_glWidget->width(), _glWidget->height()); } + if (_logOn->isChecked()) { LogDisplay::instance.render(_glWidget->width(), _glWidget->height()); } // Show chat entry field if (_chatEntryOn) { diff --git a/interface/src/Log.cpp b/interface/src/Log.cpp deleted file mode 100644 index 9b57df1694..0000000000 --- a/interface/src/Log.cpp +++ /dev/null @@ -1,321 +0,0 @@ -// -// Log.cpp -// interface -// -// Created by Tobias Schwinger on 4/14/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include "Log.h" - -#include "InterfaceConfig.h" - -#include -#include - -#include "Util.h" -#include "ui/TextRenderer.h" - -namespace { - // anonymous namespace - everything in here only exists within this very .cpp file - // just as 'static' on every effective line in plain C - - unsigned const CHARACTER_BUFFER_SIZE = 16384; // number of character that are buffered - unsigned const LINE_BUFFER_SIZE = 256; // number of lines that are buffered - unsigned const MAX_MESSAGE_LENGTH = 512; // maximum number of characters for a message - - const char* FONT_FAMILY = SANS_FONT_FAMILY; - - bool const TEXT_MONOSPACED = true; - - float const TEXT_RED = 0.7f; - float const TEXT_GREEN = 0.6f; - float const TEXT_BLUE = 1.0f; - - // magic constants from the GLUT spec - // http://www.opengl.org/resources/libraries/glut/spec3/node78.html - // ultimately this stuff should be in Util.h?? - float const CHAR_UP = 119.05f; - float const CHAR_DOWN = 33.33f; - float const CHAR_WIDTH = 104.76f; - // derived values - float const CHAR_HEIGHT = CHAR_UP + CHAR_DOWN; - float const CHAR_FRACT_BASELINE = CHAR_DOWN / CHAR_HEIGHT; - - // unsigned integer division rounded towards infinity - unsigned divRoundUp(unsigned l, unsigned r) { return (l + r - 1) / r; } -} - -Log::Log(FILE* tPipeTo, unsigned bufferedLines, - unsigned defaultLogWidth, unsigned defaultCharWidth, unsigned defaultCharHeight) : - - _ptrStream(tPipeTo), - _arrChars(0l), - _arrLines(0l), - _valLogWidth(defaultLogWidth) { - - pthread_mutex_init(& _mtx, 0l); - - // allocate twice as much (so we have spare space for a copy not to block - // logging from other threads during 'render') - _arrChars = new char[CHARACTER_BUFFER_SIZE * 2]; - _ptrCharsEnd = _arrChars + CHARACTER_BUFFER_SIZE; - _arrLines = new char*[LINE_BUFFER_SIZE * 2]; - _ptrLinesEnd = _arrLines + LINE_BUFFER_SIZE; - - // initialize the log to all empty lines - _arrChars[0] = '\0'; - _itrWritePos = _arrChars; - _itrWriteLineStart = _arrChars; - _itrLastLine = _arrLines; - _valWrittenInLine = 0; - memset(_arrLines, 0, LINE_BUFFER_SIZE * sizeof(char*)); - - setCharacterSize(defaultCharWidth, defaultCharHeight); -} - - -Log::~Log() { - - delete[] _arrChars; - delete[] _arrLines; -} - -inline void Log::addMessage(char const* ptr) { - - // precondition: mutex is locked so noone gets in our way - - // T-pipe, if requested - if (_ptrStream != 0l) { - fprintf(_ptrStream, "%s", ptr); - } - - while (*ptr != '\0') { - // process the characters - char c = *ptr++; - - if (c == '\t') { - - // found TAB -> write SPACE - c = ' '; - - } else if (c == '\n') { - - // found LF -> write NUL (c == '\0' tells us to wrap, below) - c = '\0'; - } - *_itrWritePos++ = c; - - if (_itrWritePos == _ptrCharsEnd) { - // reached the end of the circular character buffer? -> start over - _itrWritePos = _arrChars; - } - - if (++_valWrittenInLine >= _valLineLength || c == '\0') { - - // new line? store its start to the line buffer and mark next line as empty - ++_itrLastLine; - - if (_itrLastLine == _ptrLinesEnd) { - _itrLastLine = _arrLines; - _itrLastLine[1] = 0l; - } else if (_itrLastLine + 1 != _ptrLinesEnd) { - _itrLastLine[1] = 0l; - } else { - _arrLines[0] = 0l; - } - *_itrLastLine = _itrWriteLineStart; - - // debug mode: make sure all line pointers we write here are valid - assert(! (_itrLastLine < _arrLines || _itrLastLine >= _ptrLinesEnd)); - assert(! (*_itrLastLine < _arrChars || *_itrLastLine >= _ptrCharsEnd)); - - // terminate line, unless done already - if (c != '\0') { - *_itrWritePos++ = '\0'; - - if (_itrWritePos == _ptrCharsEnd) { - _itrWritePos = _arrChars; - } - } - - // remember start position in character buffer for next line and reset character count - _itrWriteLineStart = _itrWritePos; - _valWrittenInLine = 0; - } - } - -} - -int Log::vprint(char const* fmt, va_list args) { - pthread_mutex_lock(& _mtx); - - // print to buffer - char buf[MAX_MESSAGE_LENGTH]; - int n = vsnprintf(buf, MAX_MESSAGE_LENGTH, fmt, args); - if (n > 0) { - - // all fine? log the message - addMessage(buf); - - } else { - - // error? -> mutter on stream or stderr - fprintf(_ptrStream != 0l ? _ptrStream : stderr, - "Log: Failed to log message with format string = \"%s\".\n", fmt); - } - - pthread_mutex_unlock(& _mtx); - return n; -} - -void Log::operator()(char const* fmt, ...) { - - va_list args; - va_start(args,fmt); - vprint(fmt, args); - va_end(args); -} - -void Log::setLogWidth(unsigned pixels) { - - pthread_mutex_lock(& _mtx); - _valLogWidth = pixels; - _valLineLength = _valLogWidth / _valCharWidth; - pthread_mutex_unlock(& _mtx); -} - -void Log::setCharacterSize(unsigned width, unsigned height) { - - pthread_mutex_lock(& _mtx); - _valCharWidth = width; - _valCharHeight = height; - _valCharYoffset = height * CHAR_FRACT_BASELINE; - _valCharScale = float(width) / CHAR_WIDTH; - _valCharAspect = (height * CHAR_WIDTH) / (width * CHAR_HEIGHT); - _valLineLength = _valLogWidth / _valCharWidth; - pthread_mutex_unlock(& _mtx); -} - -static TextRenderer* textRenderer() { - static TextRenderer* renderer = new TextRenderer(FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT); - return renderer; -} - -void Log::render(unsigned screenWidth, unsigned screenHeight) { - - // rendering might take some time, so create a local copy of the portion we need - // instead of having to hold the mutex all the time - pthread_mutex_lock(& _mtx); - - // determine number of visible lines - unsigned showLines = divRoundUp(screenHeight, _valCharHeight); - - char** lastLine = _itrLastLine; - char** firstLine = _itrLastLine; - - if (! *lastLine) { - // empty log - pthread_mutex_unlock(& _mtx); - return; - } - - // scan for first line - for (int n = 2; n <= showLines; ++n) { - - char** prevFirstLine = firstLine; - --firstLine; - if (firstLine < _arrLines) { - firstLine = _ptrLinesEnd - 1; - } - if (! *firstLine) { - firstLine = prevFirstLine; - showLines = n - 1; - break; - } - - // debug mode: make sure all line pointers we find here are valid - assert(! (firstLine < _arrLines || firstLine >= _ptrLinesEnd)); - assert(! (*firstLine < _arrChars || *firstLine >= _ptrCharsEnd)); - } - - // copy the line buffer portion into a contiguous region at _ptrLinesEnd - if (firstLine <= lastLine) { - - memcpy(_ptrLinesEnd, firstLine, showLines * sizeof(char*)); - - } else { - - unsigned atEnd = _ptrLinesEnd - firstLine; - memcpy(_ptrLinesEnd, firstLine, atEnd * sizeof(char*)); - memcpy(_ptrLinesEnd + atEnd, _arrLines, (showLines - atEnd) * sizeof(char*)); - } - - // copy relevant char buffer portion and determine information to remap the pointers - char* firstChar = *firstLine; - char* lastChar = *lastLine + strlen(*lastLine) + 1; - ptrdiff_t charOffset = _ptrCharsEnd - firstChar, charOffsetBeforeFirst = 0; - if (firstChar <= lastChar) { - - memcpy(_ptrCharsEnd, firstChar, lastChar - firstChar + 1); - - } else { - - unsigned atEnd = _ptrCharsEnd - firstChar; - memcpy(_ptrCharsEnd, firstChar, atEnd); - memcpy(_ptrCharsEnd + atEnd, _arrChars, lastChar + 1 - _arrChars); - - charOffsetBeforeFirst = _ptrCharsEnd + atEnd - _arrChars; - } - - // get values for rendering - int yStep = textRenderer()->metrics().lineSpacing(); - int yStart = screenHeight - textRenderer()->metrics().descent(); - - // render text - char** line = _ptrLinesEnd + showLines; - int x = screenWidth - _valLogWidth; - - pthread_mutex_unlock(& _mtx); - // ok, we got all we need - - for (int y = yStart; y > 0; y -= yStep) { - - // debug mode: check line pointer is valid - assert(! (line < _ptrLinesEnd || line >= _ptrLinesEnd + (_ptrLinesEnd - _arrLines))); - - // get character pointer - if (--line < _ptrLinesEnd) { - break; - } - char* chars = *line; - - // debug mode: check char pointer we find is valid - assert(! (chars < _arrChars || chars >= _ptrCharsEnd)); - - // remap character pointer it to copied buffer - chars += chars >= firstChar ? charOffset : charOffsetBeforeFirst; - - // debug mode: check char pointer is still valid (in new range) - assert(! (chars < _ptrCharsEnd || chars >= _ptrCharsEnd + (_ptrCharsEnd - _arrChars))); - - // render the string - glColor3f(TEXT_RED, TEXT_GREEN, TEXT_BLUE); - textRenderer()->draw(x, y, chars); - -//fprintf(stderr, "Log::render, message = \"%s\"\n", chars); - } -} - -Log logger; - -int printLog(char const* fmt, ...) { - - int result; - va_list args; - va_start(args,fmt); - result = logger.vprint(fmt, args); - va_end(args); - return result; -} - diff --git a/interface/src/Log.h b/interface/src/Log.h deleted file mode 100644 index 30f9098bc9..0000000000 --- a/interface/src/Log.h +++ /dev/null @@ -1,80 +0,0 @@ -// -// Log.h -// interface -// -// Created by Tobias Schwinger on 4/14/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__Log__ -#define __interface__Log__ - -#include -#include -#include -#include - -class Log; - -// -// Call it as you would call 'printf'. -// -int printLog(char const* fmt, ...); - -// -// Global instance. -// -extern Log logger; - - -// -// Logging subsystem. -// -class Log { - FILE* _ptrStream; - char* _arrChars; - char* _ptrCharsEnd; - char** _arrLines; - char** _ptrLinesEnd; - - char* _itrWritePos; // character position to write to - char* _itrWriteLineStart; // character position where line being written starts - char** _itrLastLine; // last line in the log - unsigned _valWrittenInLine; // character counter for line wrapping - unsigned _valLineLength; // number of characters before line wrap - - unsigned _valLogWidth; // width of the log in pixels - unsigned _valCharWidth; // width of a character in pixels - unsigned _valCharHeight; // height of a character in pixels - unsigned _valCharYoffset; // baseline offset in pixels - float _valCharScale; // scale factor - float _valCharAspect; // aspect (h/w) - - pthread_mutex_t _mtx; - -public: - - explicit Log(FILE* tPipeTo = stdout, unsigned bufferedLines = 1024, - unsigned defaultLogWidth = 400, unsigned defaultCharWidth = 6, unsigned defaultCharHeight = 20); - ~Log(); - - void setLogWidth(unsigned pixels); - void setCharacterSize(unsigned width, unsigned height); - - void render(unsigned screenWidth, unsigned screenHeight); - - void operator()(char const* fmt, ...); - int vprint(char const* fmt, va_list); - -private: - // don't copy/assign - Log(Log const&); // = delete; - Log& operator=(Log const&); // = delete; - - inline void addMessage(char const*); - - friend class LogStream; // for optional iostream-style interface that has to be #included separately -}; - -#endif - diff --git a/interface/src/LogDisplay.cpp b/interface/src/LogDisplay.cpp new file mode 100644 index 0000000000..61ab9aa415 --- /dev/null +++ b/interface/src/LogDisplay.cpp @@ -0,0 +1,306 @@ +// +// LogDisplay.cpp +// interface +// +// Created by Tobias Schwinger on 4/14/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#include "LogDisplay.h" + +#include +#include +#include + +#include "Util.h" + +using namespace std; +FILE* const LogDisplay::DEFAULT_STREAM = stdout; + +// +// Singleton constructor +// +LogDisplay LogDisplay::instance; + +// +// State management +// + +LogDisplay::LogDisplay() : + + _textRenderer(MONO_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT), + _stream(DEFAULT_STREAM), + _chars(0l), + _lines(0l), + _logWidth(DEFAULT_CONSOLE_WIDTH) { + + pthread_mutex_init(& _mutex, 0l); + + // allocate twice as much (so we have spare space for a copy not to block + // logging from other threads during 'render') + _chars = new char[CHARACTER_BUFFER_SIZE * 2]; + _charsEnd = _chars + CHARACTER_BUFFER_SIZE; + _lines = new char*[LINE_BUFFER_SIZE * 2]; + _linesEnd = _lines + LINE_BUFFER_SIZE; + + // initialize the log to all empty lines + _chars[0] = '\0'; + _writePos = _chars; + _writeLineStartPos = _chars; + _lastLinePos = _lines; + _writtenInLine = 0; + memset(_lines, 0, LINE_BUFFER_SIZE * sizeof(char*)); + + setCharacterSize(DEFAULT_CHAR_WIDTH, DEFAULT_CHAR_HEIGHT); + + printLog = & printLogHandler; +} + + +LogDisplay::~LogDisplay() { + + delete[] _chars; + delete[] _lines; +} + +void LogDisplay::setStream(FILE* stream) { + + pthread_mutex_lock(& _mutex); + _stream = stream; + pthread_mutex_unlock(& _mutex); +} + +void LogDisplay::setLogWidth(unsigned pixels) { + + pthread_mutex_lock(& _mutex); + _logWidth = pixels; + _lineLength = _logWidth / _charWidth; + pthread_mutex_unlock(& _mutex); +} + +void LogDisplay::setCharacterSize(unsigned width, unsigned height) { + + pthread_mutex_lock(& _mutex); + _charWidth = width; + _charHeight = height; + _lineLength = _logWidth / _charWidth; + pthread_mutex_unlock(& _mutex); +} + +// +// Logging +// + +int LogDisplay::printLogHandler(char const* fmt, ...) { + + va_list args; + int n; + char buf[MAX_MESSAGE_LENGTH]; + va_start(args,fmt); + + // print to buffer + n = vsnprintf(buf, MAX_MESSAGE_LENGTH, fmt, args); + if (n > 0) { + + // all fine? log the message + instance.addMessage(buf); + + } else { + + // error? -> mutter on stream or stderr + fprintf(instance._stream != 0l ? instance._stream : stderr, + "Log: Failed to log message with format string = \"%s\".\n", fmt); + } + + va_end(args); + return n; +} + +inline void LogDisplay::addMessage(char const* ptr) { + + pthread_mutex_lock(& _mutex); + + // T-pipe, if requested + if (_stream != 0l) { + fprintf(_stream, "%s", ptr); + } + + while (*ptr != '\0') { + // process the characters + char c = *ptr++; + + if (c == '\t') { + + // found TAB -> write SPACE + c = ' '; + + } else if (c == '\n') { + + // found LF -> write NUL (c == '\0' tells us to wrap, below) + c = '\0'; + } + *_writePos++ = c; + + if (_writePos == _charsEnd) { + // reached the end of the circular character buffer? -> start over + _writePos = _chars; + } + + if (++_writtenInLine >= _lineLength || c == '\0') { + + // new line? store its start to the line buffer and mark next line as empty + ++_lastLinePos; + + if (_lastLinePos == _linesEnd) { + _lastLinePos = _lines; + _lastLinePos[1] = 0l; + } else if (_lastLinePos + 1 != _linesEnd) { + _lastLinePos[1] = 0l; + } else { + _lines[0] = 0l; + } + *_lastLinePos = _writeLineStartPos; + + // debug mode: make sure all line pointers we write here are valid + assert(! (_lastLinePos < _lines || _lastLinePos >= _linesEnd)); + assert(! (*_lastLinePos < _chars || *_lastLinePos >= _charsEnd)); + + // terminate line, unless done already + if (c != '\0') { + *_writePos++ = '\0'; + + if (_writePos == _charsEnd) { + _writePos = _chars; + } + } + + // remember start position in character buffer for next line and reset character count + _writeLineStartPos = _writePos; + _writtenInLine = 0; + } + } + + pthread_mutex_unlock(& _mutex); +} + +// +// Rendering +// + +void LogDisplay::render(unsigned screenWidth, unsigned screenHeight) { + + // rendering might take some time, so create a local copy of the portion we need + // instead of having to hold the mutex all the time + pthread_mutex_lock(& _mutex); + + // determine number of visible lines (integer division rounded up) + unsigned showLines = (screenHeight + _charHeight - 1) / _charHeight; + + char** lastLine = _lastLinePos; + char** firstLine = _lastLinePos; + + if (! *lastLine) { + // empty log + pthread_mutex_unlock(& _mutex); + return; + } + + // scan for first line + for (int n = 2; n <= showLines; ++n) { + + char** prevFirstLine = firstLine; + --firstLine; + if (firstLine < _lines) { + firstLine = _linesEnd - 1; + } + if (! *firstLine) { + firstLine = prevFirstLine; + showLines = n - 1; + break; + } + + // debug mode: make sure all line pointers we find here are valid + assert(! (firstLine < _lines || firstLine >= _linesEnd)); + assert(! (*firstLine < _chars || *firstLine >= _charsEnd)); + } + + // copy the line buffer portion into a contiguous region at _linesEnd + if (firstLine <= lastLine) { + + memcpy(_linesEnd, firstLine, showLines * sizeof(char*)); + + } else { + + unsigned atEnd = _linesEnd - firstLine; + memcpy(_linesEnd, firstLine, atEnd * sizeof(char*)); + memcpy(_linesEnd + atEnd, _lines, (showLines - atEnd) * sizeof(char*)); + } + + // copy relevant char buffer portion and determine information to remap the pointers + char* firstChar = *firstLine; + char* lastChar = *lastLine + strlen(*lastLine) + 1; + ptrdiff_t charOffset = _charsEnd - firstChar, charOffsetBeforeFirst = 0; + if (firstChar <= lastChar) { + + memcpy(_charsEnd, firstChar, lastChar - firstChar + 1); + + } else { + + unsigned atEnd = _charsEnd - firstChar; + memcpy(_charsEnd, firstChar, atEnd); + memcpy(_charsEnd + atEnd, _chars, lastChar + 1 - _chars); + + charOffsetBeforeFirst = _charsEnd + atEnd - _chars; + } + + // determine geometry information from font metrics + QFontMetrics const& fontMetrics = _textRenderer.metrics(); + int yStep = fontMetrics.lineSpacing(); + // scale + float xScale = float(_charWidth) / fontMetrics.width('*'); + float yScale = float(_charHeight) / yStep; + // scaled translation + int xStart = int((screenWidth - _logWidth) / xScale); + int yStart = screenHeight / yScale - fontMetrics.descent(); + + // first line to render + char** line = _linesEnd + showLines; + + // ok, now the lock can be released - we have all we need + // and won't hold it while talking to OpenGL + pthread_mutex_unlock(& _mutex); + + glPushMatrix(); + glScalef(xScale, yScale, 1.0f); + glColor3ub(GLubyte(TEXT_COLOR >> 16), + GLubyte((TEXT_COLOR >> 8) & 0xff), + GLubyte(TEXT_COLOR & 0xff)); + for (int y = yStart; y > 0; y -= yStep) { + + // debug mode: check line pointer is valid + assert(! (line < _linesEnd || line >= _linesEnd + (_linesEnd - _lines))); + + // get character pointer + if (--line < _linesEnd) { + break; + } + char* chars = *line; + + // debug mode: check char pointer we find is valid + assert(! (chars < _chars || chars >= _charsEnd)); + + // remap character pointer it to copied buffer + chars += chars >= firstChar ? charOffset : charOffsetBeforeFirst; + + // debug mode: check char pointer is still valid (in new range) + assert(! (chars < _charsEnd || chars >= _charsEnd + (_charsEnd - _chars))); + + // render the string + _textRenderer.draw(xStart, y, chars); + +//fprintf(stderr, "LogDisplay::render, message = \"%s\"\n", chars); + } + glPopMatrix(); +} + + diff --git a/interface/src/LogDisplay.h b/interface/src/LogDisplay.h new file mode 100644 index 0000000000..625e84be25 --- /dev/null +++ b/interface/src/LogDisplay.h @@ -0,0 +1,80 @@ +// +// LogDisplay.h +// interface +// +// Created by Tobias Schwinger on 4/14/13. +// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. +// + +#ifndef __interface__LogDisplay__ +#define __interface__LogDisplay__ + +#include +#include + +#include "Log.h" +#include "ui/TextRenderer.h" + +class LogDisplay { +public: + + static LogDisplay instance; + + void render(unsigned screenWidth, unsigned screenHeight); + + // settings + + static unsigned const TEXT_COLOR = 0xb299ff; // text foreground color (bytes, RGB) + + static FILE* const DEFAULT_STREAM; // = stdout; // stream to also log to (defined in .cpp) + static unsigned const DEFAULT_CHAR_WIDTH = 7; // width of a single character + static unsigned const DEFAULT_CHAR_HEIGHT = 16; // height of a single character + static unsigned const DEFAULT_CONSOLE_WIDTH = 400; // width of the (right-aligned) log console + + void setStream(FILE* stream); + void setLogWidth(unsigned pixels); + void setCharacterSize(unsigned width, unsigned height); + + // limits + + static unsigned const CHARACTER_BUFFER_SIZE = 16384; // number of character that are buffered + static unsigned const LINE_BUFFER_SIZE = 256; // number of lines that are buffered + static unsigned const MAX_MESSAGE_LENGTH = 512; // maximum number of characters for a message + +private: + // use static 'instance' to access the single instance + LogDisplay(); + ~LogDisplay(); + + // don't copy/assign + LogDisplay(LogDisplay const&); // = delete; + LogDisplay& operator=(LogDisplay const&); // = delete; + + // format and log message - entrypoint used to replace global 'printLog' + static int static printLogHandler(char const* fmt, ...); + + // log formatted message (called by printLogHandler) + inline void addMessage(char const*); + + TextRenderer _textRenderer; + FILE* _stream; // FILE as secondary destination for log messages + char* _chars; // character buffer base address + char* _charsEnd; // character buffer, exclusive end + char** _lines; // line buffer base address + char** _linesEnd; // line buffer, exclusive end + + char* _writePos; // character position to write to + char* _writeLineStartPos; // character position where line being written starts + char** _lastLinePos; // last line in the log + unsigned _writtenInLine; // character counter for line wrapping + unsigned _lineLength; // number of characters before line wrap + + unsigned _logWidth; // width of the log in pixels + unsigned _charWidth; // width of a character in pixels + unsigned _charHeight; // height of a character in pixels + + pthread_mutex_t _mutex; +}; + +#endif + diff --git a/interface/src/LogStream.h b/interface/src/LogStream.h deleted file mode 100644 index 88e5d4fff0..0000000000 --- a/interface/src/LogStream.h +++ /dev/null @@ -1,106 +0,0 @@ -// -// LogStream.h -// interface -// -// Created by Tobias Schwinger on 4/17/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __interface__LogStream__ -#define __interface__LogStream__ - -#include - -#include "Log.h" - -// -// Makes the logging facility accessible as a C++ stream. -// -// Example: -// -// // somewhere central - ideally one per thread (else pass 'true' as -// // second constructor argument and compromise some efficiency) -// LogStream lOut(printLog); -// -// // elsewhere: -// lOut << "Hello there!" << std::endl; -// -class LogStream { - std::ostringstream _objOutStream; - Log& _refLog; - bool _flgThreadSafe; -public: - inline LogStream(Log& log, bool threadSafe = false); - - class StreamRef; friend class StreamRef; - - template< typename T > friend inline LogStream::StreamRef const operator<<(LogStream&, T const&); - -private: - // don't - LogStream(LogStream const&); // = delete; - LogStream& operator=(LogStream const&); // = delete; - - inline void ostreamBegin(); - inline void ostreamEnd(); -}; - -inline LogStream::LogStream(Log& log, bool threadSafe) : - _objOutStream(std::ios_base::out), _refLog(log), _flgThreadSafe(threadSafe) { } - -inline void LogStream::ostreamBegin() { - - if (_flgThreadSafe) { - // the user wants to share this LogStream among threads, - // so lock the global log here, already - pthread_mutex_lock(& _refLog._mtx); - } - _objOutStream.str(""); -} - -inline void LogStream::ostreamEnd() { - - if (! _flgThreadSafe) { - // haven't locked, so far (we have memory for each thread) - pthread_mutex_lock(& _refLog._mtx); - } - _refLog.addMessage(_objOutStream.str().c_str()); - pthread_mutex_unlock(& _refLog._mtx); -} - - -// -// The Log::StreamRef class makes operator<< work. It... -// -class LogStream::StreamRef { - mutable LogStream* _ptrLogStream; - typedef std::ostream& (*manipulator)(std::ostream&); - - friend class LogStream; - - template< typename T > friend inline LogStream::StreamRef const operator<<(LogStream&, T const&); - StreamRef(LogStream* log) : _ptrLogStream(log) { } -public: - // ...forwards << operator calls to stringstream... - template< typename T > StreamRef const operator<<(T const& x) const { _ptrLogStream->_objOutStream << x; return *this; } - // ...has to dance around to make manipulators (such as std::hex, std::endl) work... - StreamRef const operator<<(manipulator x) const { _ptrLogStream->_objOutStream << x; return *this; } - // ...informs the logger that a stream has ended when it has the responsibility... - ~StreamRef() { if (_ptrLogStream != 0l) { _ptrLogStream->ostreamEnd(); } } - // ...which is passed on upon copy. - StreamRef(StreamRef const& other) : _ptrLogStream(other._ptrLogStream) { other._ptrLogStream = 0l; } - -private: - // don't - StreamRef& operator=(StreamRef const&); // = delete; -}; - -template< typename T > inline LogStream::StreamRef const operator<<(LogStream& s, T const& x) { - - s.ostreamBegin(); - s._objOutStream << x; - return LogStream::StreamRef(& s); // calls streamEnd at the end of the stream expression -} - - -#endif diff --git a/interface/src/OGlProgram.h b/interface/src/OGlProgram.h deleted file mode 100644 index ac1ea019bd..0000000000 --- a/interface/src/OGlProgram.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef __interface__OpenGlSupport__ -#define __interface__OpenGlSupport__ - -#include "InterfaceConfig.h" -#include "Log.h" - -// -// Macro to log OpenGl errors. -// Example: oglLog( glPushMatrix() ); -// -#define oGlLog(stmt) \ - stmt; \ - { \ - GLenum e = glGetError(); \ - if (e != GL_NO_ERROR) { \ - printLog(__FILE__ ":" oGlLog_stringize(__LINE__) \ - " [OpenGL] %s\n", gluErrorString(e)); \ - } \ - } \ - (void) 0 - -#define oGlLog_stringize(x) oGlLog_stringize_i(x) -#define oGlLog_stringize_i(x) # x - -// -// Encapsulation of the otherwise lengthy call sequence to compile -// and link shading pipelines. -// -class OGlProgram { - - GLuint _hndProg; - -public: - - OGlProgram() : _hndProg(0) { } - - ~OGlProgram() { if (_hndProg != 0u) { glDeleteProgram(_hndProg); } } - - // no copy/assign - OGlProgram(OGlProgram const&); // = delete; - OGlProgram& operator=(OGlProgram const&); // = delete; - -#if 0 // let's keep this commented, for now (C++11) - - OGlProgram(OGlProgram&& disposable) : _hndProg(disposable._hndProg) { - - disposable._hndProg = 0; - } - - OGlProgram& operator=(OGlProgram&& disposable) { - - GLuint tmp = _hndProg; - _hndProg = disposable._hndProg; - disposable._hndProg = tmp; - } -#endif - - // - // Activates the executable for rendering. - // Shaders must be added and linked before this will work. - // - void activate() const { - - if (_hndProg != 0u) { - - oGlLog( glUseProgram(_hndProg) ); - } - } - - // - // Adds a shader to the program. - // - bool addShader(GLenum type, GLchar const* cString) { - - return addShader(type, 1, & cString); - } - - // - // Adds a shader to the program and logs to stderr. - // - bool addShader(GLenum type, GLsizei nStrings, GLchar const** strings) { - - if (! _hndProg && !! glCreateProgram) { - - _hndProg = glCreateProgram(); - } - if (! _hndProg) { return false; } - - GLuint s = glCreateShader(type); - glShaderSource(s, nStrings, strings, 0l); - glCompileShader(s); - GLint status; - glGetShaderiv(s, GL_COMPILE_STATUS, & status); - if (status != 0) - glAttachShader(_hndProg, s); -#ifdef NDEBUG // always fetch log in debug mode - else -#endif - fetchLog(s, glGetShaderiv, glGetShaderInfoLog); - glDeleteShader(s); - return !! status; - } - - // - // Links the program and logs to stderr. - // - bool link() { - - if (! _hndProg) { return false; } - - glLinkProgram(_hndProg); - GLint status; - glGetProgramiv(_hndProg, GL_LINK_STATUS, & status); -#ifndef NDEBUG // always fetch log in debug mode - fetchLog(_hndProg, glGetProgramiv, glGetProgramInfoLog); -#endif - if (status == 0) { -#ifdef NDEBUG // only on error in release mode - fetchLog(_hndProg, glGetProgramiv, glGetProgramInfoLog); -#endif - glDeleteProgram(_hndProg); - _hndProg = 0u; - return false; - - } else { - - return true; - } - } - -private: - - template< typename ParamFunc, typename GetLogFunc > - void fetchLog(GLint handle, ParamFunc getParam, GetLogFunc getLog) { - GLint logLength = 0; - getParam(handle, GL_INFO_LOG_LENGTH, &logLength); - if (!! logLength) { - GLchar* message = new GLchar[logLength]; - getLog(handle, logLength, 0l, message); - printLog("%s\n", message); - delete[] message; - } - } -}; - -#endif diff --git a/interface/src/Oscilloscope.cpp b/interface/src/Oscilloscope.cpp index baa173e512..5fbd747f0d 100644 --- a/interface/src/Oscilloscope.cpp +++ b/interface/src/Oscilloscope.cpp @@ -32,31 +32,33 @@ namespace { // everything in here only exists while compiling this .cpp file } -Oscilloscope::Oscilloscope(int w, int h, bool isEnabled) : +Oscilloscope::Oscilloscope(int w, int h, bool isEnabled) : enabled(isEnabled), inputPaused(false), - _valWidth(w), - _valHeight(h), - _arrSamples(0l), - _arrVertices(0l), - _valLowpass(0.4f), - _valDownsample(3) { - + _width(w), + _height(h), + _samples(0l), + _vertices(0l), + // some filtering (see details in Log.h) + _lowPassCoeff(0.4f), + // three in -> one out + _downsampleRatio(3) { + // allocate enough space for the sample data and to turn it into // vertices and since they're all 'short', do so in one shot - _arrSamples = new short[N_INT16_TO_ALLOC]; - memset(_arrSamples, 0, N_INT16_TO_ALLOC * sizeof(short)); - _arrVertices = _arrSamples + MAX_SAMPLES; + _samples = new short[N_INT16_TO_ALLOC]; + memset(_samples, 0, N_INT16_TO_ALLOC * sizeof(short)); + _vertices = _samples + MAX_SAMPLES; // initialize write positions to start of each channel's region for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) { - _arrWritePos[ch] = MAX_SAMPLES_PER_CHANNEL * ch; + _writePos[ch] = MAX_SAMPLES_PER_CHANNEL * ch; } } Oscilloscope::~Oscilloscope() { - delete[] _arrSamples; + delete[] _samples; } void Oscilloscope::addSamples(unsigned ch, short const* data, unsigned n) { @@ -70,7 +72,7 @@ void Oscilloscope::addSamples(unsigned ch, short const* data, unsigned n) { unsigned endOffs = baseOffs + MAX_SAMPLES_PER_CHANNEL; // fetch write position for this channel - unsigned writePos = _arrWritePos[ch]; + unsigned writePos = _writePos[ch]; // determine write position after adding the samples unsigned newWritePos = writePos + n; @@ -83,13 +85,13 @@ void Oscilloscope::addSamples(unsigned ch, short const* data, unsigned n) { } // copy data - memcpy(_arrSamples + writePos, data, n * sizeof(short)); + memcpy(_samples + writePos, data, n * sizeof(short)); if (n2 > 0) { - memcpy(_arrSamples + baseOffs, data + n, n2 * sizeof(short)); + memcpy(_samples + baseOffs, data + n, n2 * sizeof(short)); } // set new write position for this channel - _arrWritePos[ch] = newWritePos; + _writePos[ch] = newWritePos; } void Oscilloscope::render(int x, int y) { @@ -98,20 +100,20 @@ void Oscilloscope::render(int x, int y) { return; } - // determine lowpass / downsample factors - int lowpass = -int(std::numeric_limits::min()) * _valLowpass; - unsigned downsample = _valDownsample; + // fetch low pass factor (and convert to fix point) / downsample factor + int lowPassFixPt = -int(std::numeric_limits::min()) * _lowPassCoeff; + unsigned downsample = _downsampleRatio; // keep half of the buffer for writing and ensure an even vertex count - unsigned usedWidth = min(_valWidth, MAX_SAMPLES_PER_CHANNEL / (downsample * 2)) & ~1u; + unsigned usedWidth = min(_width, MAX_SAMPLES_PER_CHANNEL / (downsample * 2)) & ~1u; unsigned usedSamples = usedWidth * downsample; // expand samples to vertex data for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) { // for each channel: determine memory regions - short const* basePtr = _arrSamples + MAX_SAMPLES_PER_CHANNEL * ch; + short const* basePtr = _samples + MAX_SAMPLES_PER_CHANNEL * ch; short const* endPtr = basePtr + MAX_SAMPLES_PER_CHANNEL; - short const* inPtr = _arrSamples + _arrWritePos[ch]; - short* outPtr = _arrVertices + MAX_COORDS_PER_CHANNEL * ch; + short const* inPtr = _samples + _writePos[ch]; + short* outPtr = _vertices + MAX_COORDS_PER_CHANNEL * ch; int sample = 0, x = usedWidth; for (int i = int(usedSamples); --i >= 0 ;) { if (inPtr == basePtr) { @@ -119,7 +121,7 @@ void Oscilloscope::render(int x, int y) { inPtr = endPtr; } // read and (eventually) filter sample - sample += ((*--inPtr - sample) * lowpass) >> 15; + sample += ((*--inPtr - sample) * lowPassFixPt) >> 15; // write every nth as y with a corresponding x-coordinate if (i % downsample == 0) { *outPtr++ = short(--x); @@ -128,13 +130,13 @@ void Oscilloscope::render(int x, int y) { } } - // set up rendering state (vertex data lives at _arrVertices) + // set up rendering state (vertex data lives at _vertices) glLineWidth(1.0); glDisable(GL_LINE_SMOOTH); glPushMatrix(); - glTranslatef((float)x + 0.0f, (float)y + _valHeight / 2.0f, 0.0f); - glScaled(1.0f, _valHeight / 32767.0f, 1.0f); - glVertexPointer(2, GL_SHORT, 0, _arrVertices); + glTranslatef((float)x + 0.0f, (float)y + _height / 2.0f, 0.0f); + glScaled(1.0f, _height / 32767.0f, 1.0f); + glVertexPointer(2, GL_SHORT, 0, _vertices); glEnableClientState(GL_VERTEX_ARRAY); // render channel 0 diff --git a/interface/src/Oscilloscope.h b/interface/src/Oscilloscope.h index 8c0b727b6e..65616e701b 100644 --- a/interface/src/Oscilloscope.h +++ b/interface/src/Oscilloscope.h @@ -17,17 +17,43 @@ public: ~Oscilloscope(); void addSamples(unsigned ch, short const* data, unsigned n); - + void render(int x, int y); - static unsigned const MAX_CHANNELS = 3; - static unsigned const MAX_SAMPLES_PER_CHANNEL = 4096; - + // Switches: On/Off, Stop Time volatile bool enabled; volatile bool inputPaused; - void setLowpass(float w) { assert(w > 0.0f && w <= 1.0f); _valLowpass = w; } - void setDownsampling(unsigned f) { assert(f > 0); _valDownsample = f; } + // Limits + static unsigned const MAX_CHANNELS = 3; + static unsigned const MAX_SAMPLES_PER_CHANNEL = 4096; + + // Controls a simple one pole IIR low pass filter that is provided to + // reduce high frequencies aliasing (to lower ones) when downsampling. + // + // The parameter sets the influence of the input in respect to the + // feed-back signal on the output. + // + // +---------+ + // in O--------------|+ ideal |--o--------------O out + // .---|- op amp | | + // | +---------+ | + // | | + // o-------||-------o + // | | + // | __V__ + // -------------|_____|-------+ + // : : | + // 0.0 - 1.0 (GND) + // + // The values in range 0.0 - 1.0 correspond to "all closed" (input has + // no influence on the output) to "all open" (feedback has no influence + // on the output) configurations. + void setLowpassOpenness(float w) { assert(w >= 0.0f && w <= 1.0f); _lowPassCoeff = w; } + + // Sets the number of input samples per output sample. Without filtering + // just uses every nTh sample. + void setDownsampleRatio(unsigned n) { assert(n > 0); _downsampleRatio = n; } private: // don't copy/assign @@ -36,14 +62,14 @@ private: // state variables - unsigned _valWidth; - unsigned _valHeight; - short* _arrSamples; - short* _arrVertices; - unsigned _arrWritePos[MAX_CHANNELS]; + unsigned _width; + unsigned _height; + short* _samples; + short* _vertices; + unsigned _writePos[MAX_CHANNELS]; - float _valLowpass; - unsigned _valDownsample; + float _lowPassCoeff; + unsigned _downsampleRatio; }; #endif /* defined(__interface__oscilloscope__) */ diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp index e8e0222420..7934190e4c 100644 --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -14,24 +14,24 @@ #undef __interface__Starfield_impl__ Stars::Stars() : - _ptrController(0l) { - _ptrController = new starfield::Controller; + _controller(0l) { + _controller = new starfield::Controller; } Stars::~Stars() { - delete _ptrController; + delete _controller; } bool Stars::readInput(const char* url, const char* cacheFile, unsigned limit) { - return _ptrController->readInput(url, cacheFile, limit); + return _controller->readInput(url, cacheFile, limit); } bool Stars::setResolution(unsigned k) { - return _ptrController->setResolution(k); + return _controller->setResolution(k); } float Stars::changeLOD(float fraction, float overalloc, float realloc) { - return float(_ptrController->changeLOD(fraction, overalloc, realloc)); + return float(_controller->changeLOD(fraction, overalloc, realloc)); } void Stars::render(float fovY, float aspect, float nearZ, float alpha) { @@ -46,7 +46,7 @@ void Stars::render(float fovY, float aspect, float nearZ, float alpha) { // pull the modelview matrix off the GL stack glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view)); - _ptrController->render(fovDiagonal, aspect, glm::affineInverse(view), alpha); + _controller->render(fovDiagonal, aspect, glm::affineInverse(view), alpha); } diff --git a/interface/src/Stars.h b/interface/src/Stars.h index 7088bee36e..ac2abcde42 100644 --- a/interface/src/Stars.h +++ b/interface/src/Stars.h @@ -17,11 +17,7 @@ namespace starfield { class Controller; } // Starfield rendering component. // class Stars { - - starfield::Controller* _ptrController; - public: - Stars(); ~Stars(); @@ -73,6 +69,10 @@ class Stars { // don't copy/assign Stars(Stars const&); // = delete; Stars& operator=(Stars const&); // delete; + + // variables + + starfield::Controller* _controller; }; diff --git a/interface/src/starfield/Config.h b/interface/src/starfield/Config.h index 92d4a05723..c11fe68e38 100644 --- a/interface/src/starfield/Config.h +++ b/interface/src/starfield/Config.h @@ -38,7 +38,7 @@ // #include "InterfaceConfig.h" -#include "OGlProgram.h" +#include "renderer/ProgramObject.h" #include "Log.h" #include diff --git a/interface/src/starfield/Controller.h b/interface/src/starfield/Controller.h index 93dc134392..cefe46664e 100644 --- a/interface/src/starfield/Controller.h +++ b/interface/src/starfield/Controller.h @@ -55,60 +55,26 @@ namespace starfield { class Controller { - - InputVertices _seqInput; -#if STARFIELD_MULTITHREADING - mutex _mtxInput; - atomic _valTileResolution; - - mutex _mtxLodState; -#else - unsigned _valTileResolution; -#endif - double _valLodFraction; - double _valLodLowWaterMark; - double _valLodHighWaterMark; - double _valLodOveralloc; - size_t _valLodNalloc; - size_t _valLodNrender; - BrightnessLevels _seqLodBrightness; - -#if STARFIELD_MULTITHREADING - atomic _valLodBrightness; - BrightnessLevel _valLodAllocBrightness; - - atomic _ptrRenderer; - - typedef lock_guard lock; -#else - BrightnessLevel _valLodBrightness; - BrightnessLevel _valLodAllocBrightness; - - Renderer* _ptrRenderer; - - #define lock - #define _(x) -#endif - - static inline size_t toBufSize(double f) { - return size_t(floor(f + 0.5f)); - } - public: Controller() : - _valTileResolution(20), - _valLodFraction(1.0), - _valLodLowWaterMark(0.8), - _valLodHighWaterMark(1.0), - _valLodOveralloc(1.2), - _valLodNalloc(0), - _valLodNrender(0), - _valLodBrightness(0), - _valLodAllocBrightness(0), - _ptrRenderer(0l) { + _tileResolution(20), + _lodFraction(1.0), + _lodLowWaterMark(0.8), + _lodHighWaterMark(1.0), + _lodOveralloc(1.2), + _lodNalloc(0), + _lodNRender(0), + _lodBrightness(0), + _lodAllocBrightness(0), + _renderer(0l) { } +#if !STARFIELD_MULTITHREADING + #define lock + #define _(x) +#endif + bool readInput(const char* url, const char* cacheFile, unsigned limit) { InputVertices vertices; @@ -121,13 +87,13 @@ namespace starfield { // input is read, now run the entire data pipeline on the new input - { lock _(_mtxInput); + { lock _(_inputMutex); - _seqInput.swap(vertices); + _inputSequence.swap(vertices); #if STARFIELD_MULTITHREADING - unsigned k = _valTileResolution.load(memory_order_relaxed); + unsigned k = _tileResolution.load(memory_order_relaxed); #else - unsigned k = _valTileResolution; + unsigned k = _tileResolution; #endif size_t n, nRender; BrightnessLevel bMin, b; @@ -136,27 +102,27 @@ namespace starfield { // we'll have to build a new LOD state for a new total N, // ideally keeping allocation size and number of vertices - { lock _(_mtxLodState); + { lock _(_lodStateMutex); - size_t newLast = _seqInput.size() - 1; + size_t newLast = _inputSequence.size() - 1; // reciprocal change N_old/N_new tells us how to scale // the fractions - rcpChange = min(1.0, double(vertices.size()) / _seqInput.size()); + rcpChange = min(1.0, double(vertices.size()) / _inputSequence.size()); // initialization? use defaults / previously set values if (rcpChange == 0.0) { rcpChange = 1.0; - nRender = toBufSize(_valLodFraction * newLast); - n = min(newLast, toBufSize(_valLodOveralloc * nRender)); + nRender = toBufSize(_lodFraction * newLast); + n = min(newLast, toBufSize(_lodOveralloc * nRender)); } else { // cannot allocate or render more than we have - n = min(newLast, _valLodNalloc); - nRender = min(newLast, _valLodNrender); + n = min(newLast, _lodNalloc); + nRender = min(newLast, _lodNRender); } // determine new minimum brightness levels @@ -178,26 +144,26 @@ namespace starfield { } catch (...) { // rollback transaction and rethrow - vertices.swap(_seqInput); + vertices.swap(_inputSequence); throw; } // finally publish the new LOD state - { lock _(_mtxLodState); + { lock _(_lodStateMutex); - _seqLodBrightness.swap(brightness); - _valLodFraction *= rcpChange; - _valLodLowWaterMark *= rcpChange; - _valLodHighWaterMark *= rcpChange; - _valLodOveralloc *= rcpChange; - _valLodNalloc = n; - _valLodNrender = nRender; - _valLodAllocBrightness = bMin; + _lodBrightnessSequence.swap(brightness); + _lodFraction *= rcpChange; + _lodLowWaterMark *= rcpChange; + _lodHighWaterMark *= rcpChange; + _lodOveralloc *= rcpChange; + _lodNalloc = n; + _lodNRender = nRender; + _lodAllocBrightness = bMin; #if STARFIELD_MULTITHREADING - _valLodBrightness.store(b, memory_order_relaxed); + _lodBrightness.store(b, memory_order_relaxed); #else - _valLodBrightness = b; + _lodBrightness = b; #endif } } @@ -214,24 +180,24 @@ namespace starfield { // printLog("Stars.cpp: setResolution(%d)\n", k); #if STARFIELD_MULTITHREADING - if (k != _valTileResolution.load(memory_order_relaxed)) + if (k != _tileResolution.load(memory_order_relaxed)) #else - if (k != _valTileResolution) + if (k != _tileResolution) #endif - { lock _(_mtxInput); + { lock _(_inputMutex); unsigned n; BrightnessLevel b, bMin; - { lock _(_mtxLodState); + { lock _(_lodStateMutex); - n = _valLodNalloc; + n = _lodNalloc; #if STARFIELD_MULTITHREADING - b = _valLodBrightness.load(memory_order_relaxed); + b = _lodBrightness.load(memory_order_relaxed); #else - b = _valLodBrightness; + b = _lodBrightness; #endif - bMin = _valLodAllocBrightness; + bMin = _lodAllocBrightness; } this->retile(n, k, b, bMin); @@ -242,25 +208,6 @@ namespace starfield { } } - private: - - void retile(size_t n, unsigned k, - BrightnessLevel b, BrightnessLevel bMin) { - - Tiling tiling(k); - VertexOrder scanner(tiling); - radix2InplaceSort(_seqInput.begin(), _seqInput.end(), scanner); - -// printLog( -// "Stars.cpp: recreateRenderer(%d, %d, %d, %d)\n", n, k, b, bMin); - - recreateRenderer(n, k, b, bMin); - - _valTileResolution = k; - } - - public: - double changeLOD(double factor, double overalloc, double realloc) { assert(overalloc >= realloc && realloc >= 0.0); @@ -273,13 +220,13 @@ namespace starfield { BrightnessLevel bMin, b; double fraction, lwm, hwm; - { lock _(_mtxLodState); + { lock _(_lodStateMutex); // acuire a consistent copy of the current LOD state - fraction = _valLodFraction; - lwm = _valLodLowWaterMark; - hwm = _valLodHighWaterMark; - size_t last = _seqLodBrightness.size() - 1; + fraction = _lodFraction; + lwm = _lodLowWaterMark; + hwm = _lodHighWaterMark; + size_t last = _lodBrightnessSequence.size() - 1; // apply factor fraction = max(0.0, min(1.0, fraction * factor)); @@ -288,23 +235,23 @@ namespace starfield { // threshold double oaFract = std::min(fraction * (1.0 + overalloc), 1.0); n = toBufSize(oaFract * last); - bMin = _seqLodBrightness[n]; + bMin = _lodBrightnessSequence[n]; n = std::upper_bound( - _seqLodBrightness.begin() + n - 1, - _seqLodBrightness.end(), - bMin, GreaterBrightness() ) - _seqLodBrightness.begin(); + _lodBrightnessSequence.begin() + n - 1, + _lodBrightnessSequence.end(), + bMin, GreaterBrightness() ) - _lodBrightnessSequence.begin(); // also determine number of vertices to render and brightness nRender = toBufSize(fraction * last); // Note: nRender does not have to be accurate - b = _seqLodBrightness[nRender]; + b = _lodBrightnessSequence[nRender]; // this setting controls the renderer, also keep b as the // brightness becomes volatile as soon as the mutex is // released, so keep b #if STARFIELD_MULTITHREADING - _valLodBrightness.store(b, memory_order_relaxed); + _lodBrightness.store(b, memory_order_relaxed); #else - _valLodBrightness = b; + _lodBrightness = b; #endif // printLog("Stars.cpp: " @@ -313,69 +260,54 @@ namespace starfield { // will not have to reallocate? set new fraction right away // (it is consistent with the rest of the state in this case) - if (fraction >= _valLodLowWaterMark - && fraction <= _valLodHighWaterMark) { + if (fraction >= _lodLowWaterMark + && fraction <= _lodHighWaterMark) { - _valLodFraction = fraction; + _lodFraction = fraction; return fraction; } } // reallocate - { lock _(_mtxInput); + { lock _(_inputMutex); - recreateRenderer(n, _valTileResolution, b, bMin); + recreateRenderer(n, _tileResolution, b, bMin); // printLog("Stars.cpp: LOD reallocation\n"); // publish new lod state - { lock _(_mtxLodState); + { lock _(_lodStateMutex); - _valLodNalloc = n; - _valLodNrender = nRender; + _lodNalloc = n; + _lodNRender = nRender; - _valLodFraction = fraction; - _valLodLowWaterMark = fraction * (1.0 - realloc); - _valLodHighWaterMark = fraction * (1.0 + realloc); - _valLodOveralloc = fraction * (1.0 + overalloc); - _valLodAllocBrightness = bMin; + _lodFraction = fraction; + _lodLowWaterMark = fraction * (1.0 - realloc); + _lodHighWaterMark = fraction * (1.0 + realloc); + _lodOveralloc = fraction * (1.0 + overalloc); + _lodAllocBrightness = bMin; } } return fraction; } - private: - - void recreateRenderer(size_t n, unsigned k, - BrightnessLevel b, BrightnessLevel bMin) { - -#if STARFIELD_MULTITHREADING - delete _ptrRenderer.exchange(new Renderer(_seqInput, n, k, b, bMin) ); -#else - delete _ptrRenderer; - _ptrRenderer = new Renderer(_seqInput, n, k, b, bMin); -#endif - } - - public: - void render(float perspective, float angle, mat4 const& orientation, float alpha) { #if STARFIELD_MULTITHREADING // check out renderer - Renderer* renderer = _ptrRenderer.exchange(0l); + Renderer* renderer = _renderer.exchange(0l); #else - Renderer* renderer = _ptrRenderer; + Renderer* renderer = _renderer; #endif // have it render if (renderer != 0l) { #if STARFIELD_MULTITHREADING - BrightnessLevel b = _valLodBrightness.load(memory_order_relaxed); + BrightnessLevel b = _lodBrightness.load(memory_order_relaxed); #else - BrightnessLevel b = _valLodBrightness; + BrightnessLevel b = _lodBrightness; #endif renderer->render(perspective, angle, orientation, b, alpha); } @@ -383,7 +315,7 @@ namespace starfield { #if STARFIELD_MULTITHREADING // check in - or dispose if there is a new one Renderer* newOne = 0l; - if (! _ptrRenderer.compare_exchange_strong(newOne, renderer)) { + if (! _renderer.compare_exchange_strong(newOne, renderer)) { assert(!! newOne); delete renderer; @@ -396,6 +328,37 @@ namespace starfield { private: + void retile(size_t n, unsigned k, + BrightnessLevel b, BrightnessLevel bMin) { + + Tiling tiling(k); + VertexOrder scanner(tiling); + radix2InplaceSort(_inputSequence.begin(), _inputSequence.end(), scanner); + +// printLog( +// "Stars.cpp: recreateRenderer(%d, %d, %d, %d)\n", n, k, b, bMin); + + recreateRenderer(n, k, b, bMin); + + _tileResolution = k; + } + + void recreateRenderer(size_t n, unsigned k, + BrightnessLevel b, BrightnessLevel bMin) { + +#if STARFIELD_MULTITHREADING + delete _renderer.exchange(new Renderer(_inputSequence, n, k, b, bMin) ); +#else + delete _renderer; + _renderer = new Renderer(_inputSequence, n, k, b, bMin); +#endif + } + + + static inline size_t toBufSize(double f) { + return size_t(floor(f + 0.5f)); + } + struct BrightnessSortScanner : Radix2IntegerScanner { typedef Radix2IntegerScanner base; @@ -420,6 +383,39 @@ namespace starfield { radix2InplaceSort(dst.begin(), dst.end(), BrightnessSortScanner()); } + InputVertices _inputSequence; +#if STARFIELD_MULTITHREADING + mutex _inputMutex; + atomic _tileResolution; + + mutex _lodStateMutex; +#else + unsigned _tileResolution; +#endif + double _lodFraction; + double _lodLowWaterMark; + double _lodHighWaterMark; + double _lodOveralloc; + size_t _lodNalloc; + size_t _lodNRender; + BrightnessLevels _lodBrightnessSequence; + +#if STARFIELD_MULTITHREADING + atomic _lodBrightness; + BrightnessLevel _lodAllocBrightness; + + atomic _renderer; + + typedef lock_guard lock; +#else + BrightnessLevel _lodBrightness; + BrightnessLevel _lodAllocBrightness; + + Renderer* _renderer; + + #undef lock + #undef _ +#endif }; } diff --git a/interface/src/starfield/Loader.h b/interface/src/starfield/Loader.h index 79ae7f7700..e4e87516ea 100644 --- a/interface/src/starfield/Loader.h +++ b/interface/src/starfield/Loader.h @@ -23,42 +23,32 @@ namespace starfield { class Loader : UrlReader { - - InputVertices* _ptrVertices; - unsigned _valLimit; - - unsigned _valLineNo; - char const* _strUrl; - - unsigned _valRecordsRead; - BrightnessLevel _valMinBrightness; public: bool loadVertices( InputVertices& destination, char const* url, char const* cacheFile, unsigned limit) { - _ptrVertices = & destination; - _valLimit = limit; + _vertices = & destination; + _limit = limit; #if STARFIELD_SAVE_MEMORY - if (_valLimit == 0 || _valLimit > 60000u) - _valLimit = 60000u; + if (_limit == 0 || _limit > 60000u) + _limit = 60000u; #endif - _strUrl = url; // in case we fail early + _urlStr = url; // in case we fail early if (! UrlReader::readUrl(url, *this, cacheFile)) { printLog("%s:%d: %s\n", - _strUrl, _valLineNo, getError()); + _urlStr, _lineNo, getError()); return false; } - printLog("Loaded %u stars.\n", _valRecordsRead); + printLog("Loaded %u stars.\n", _recordsRead); return true; } protected: - friend class UrlReader; void begin(char const* url, @@ -66,13 +56,13 @@ namespace starfield { int64_t size, int64_t stardate) { - _valLineNo = 0u; - _strUrl = url; // new value in http redirect + _lineNo = 0u; + _urlStr = url; // new value in http redirect - _valRecordsRead = 0u; + _recordsRead = 0u; - _ptrVertices->clear(); - _ptrVertices->reserve(_valLimit); + _vertices->clear(); + _vertices->reserve(_limit); // printLog("Stars.cpp: loader begin %s\n", url); } @@ -88,7 +78,7 @@ namespace starfield { for (; next != end && isspace(*next); ++next); consumed = next - input; line = next; - ++_valLineNo; + ++_lineNo; for (; next != end && *next != '\n' && *next != '\r'; ++next); if (next == end) return consumed; @@ -109,12 +99,12 @@ namespace starfield { storeVertex(azi, alt, c); } - ++_valRecordsRead; + ++_recordsRead; } else { printLog("Stars.cpp:%d: Bad input from %s\n", - _valLineNo, _strUrl); + _lineNo, _urlStr); } } @@ -126,7 +116,7 @@ namespace starfield { private: - bool atLimit() { return _valLimit > 0u && _valRecordsRead >= _valLimit; } + bool atLimit() { return _limit > 0u && _recordsRead >= _limit; } bool spaceFor(BrightnessLevel b) { @@ -136,44 +126,55 @@ namespace starfield { // just reached the limit? -> establish a minimum heap and // remember the brightness at its top - if (_valRecordsRead == _valLimit) { + if (_recordsRead == _limit) { // printLog("Stars.cpp: vertex limit reached -> heap mode\n"); make_heap( - _ptrVertices->begin(), _ptrVertices->end(), + _vertices->begin(), _vertices->end(), GreaterBrightness() ); - _valMinBrightness = getBrightness( - _ptrVertices->begin()->getColor() ); + _minBrightness = getBrightness( + _vertices->begin()->getColor() ); } // not interested? say so - if (_valMinBrightness >= b) + if (_minBrightness >= b) return false; // otherwise free up space for the new vertex pop_heap( - _ptrVertices->begin(), _ptrVertices->end(), + _vertices->begin(), _vertices->end(), GreaterBrightness() ); - _ptrVertices->pop_back(); + _vertices->pop_back(); return true; } void storeVertex(float azi, float alt, unsigned color) { - _ptrVertices->push_back(InputVertex(azi, alt, color)); + _vertices->push_back(InputVertex(azi, alt, color)); if (atLimit()) { push_heap( - _ptrVertices->begin(), _ptrVertices->end(), + _vertices->begin(), _vertices->end(), GreaterBrightness() ); - _valMinBrightness = getBrightness( - _ptrVertices->begin()->getColor() ); + _minBrightness = getBrightness( + _vertices->begin()->getColor() ); } } + + // variables + + InputVertices* _vertices; + unsigned _limit; + + unsigned _lineNo; + char const* _urlStr; + + unsigned _recordsRead; + BrightnessLevel _minBrightness; }; } // anonymous namespace diff --git a/interface/src/starfield/data/GpuVertex.h b/interface/src/starfield/data/GpuVertex.h index 6de3b5a15f..c194e8cdb9 100644 --- a/interface/src/starfield/data/GpuVertex.h +++ b/interface/src/starfield/data/GpuVertex.h @@ -18,18 +18,12 @@ namespace starfield { class GpuVertex { - - unsigned _valColor; - float _valX; - float _valY; - float _valZ; public: - GpuVertex() { } GpuVertex(InputVertex const& in) { - _valColor = in.getColor(); + _color = in.getColor(); float azi = in.getAzimuth(); float alt = in.getAltitude(); @@ -44,7 +38,13 @@ namespace starfield { _valZ = gz * exz; } - unsigned getColor() const { return _valColor; } + unsigned getColor() const { return _color; } + + private: + unsigned _color; + float _valX; + float _valY; + float _valZ; }; } // anonymous namespace diff --git a/interface/src/starfield/data/InputVertex.h b/interface/src/starfield/data/InputVertex.h index 670056bd74..ca247a3ba4 100644 --- a/interface/src/starfield/data/InputVertex.h +++ b/interface/src/starfield/data/InputVertex.h @@ -18,15 +18,11 @@ namespace starfield { class InputVertex { - - unsigned _valColor; - float _valAzimuth; - float _valAltitude; public: InputVertex(float azimuth, float altitude, unsigned color) { - _valColor = ((color >> 16) & 0xffu) | (color & 0xff00u) | + _color = ((color >> 16) & 0xffu) | (color & 0xff00u) | ((color << 16) & 0xff0000u) | 0xff000000u; azimuth = angleConvert(azimuth); @@ -34,13 +30,18 @@ namespace starfield { angleHorizontalPolar(azimuth, altitude); - _valAzimuth = azimuth; - _valAltitude = altitude; + _azimuth = azimuth; + _altitude = altitude; } - float getAzimuth() const { return _valAzimuth; } - float getAltitude() const { return _valAltitude; } - unsigned getColor() const { return _valColor; } + float getAzimuth() const { return _azimuth; } + float getAltitude() const { return _altitude; } + unsigned getColor() const { return _color; } + + private: + unsigned _color; + float _azimuth; + float _altitude; }; typedef std::vector InputVertices; diff --git a/interface/src/starfield/data/Tile.h b/interface/src/starfield/data/Tile.h index 6d51921ce9..a7c26c7c8f 100644 --- a/interface/src/starfield/data/Tile.h +++ b/interface/src/starfield/data/Tile.h @@ -25,6 +25,7 @@ namespace starfield { BrightnessLevel lod; nuint flags; + // flags static uint16_t const checked = 1; static uint16_t const visited = 2; static uint16_t const render = 4; diff --git a/interface/src/starfield/renderer/Renderer.h b/interface/src/starfield/renderer/Renderer.h index 97b565c767..75f93e0367 100644 --- a/interface/src/starfield/renderer/Renderer.h +++ b/interface/src/starfield/renderer/Renderer.h @@ -13,8 +13,6 @@ #error "This is an implementation file - not intended for direct inclusion." #endif -#include "renderer/ProgramObject.h" - #include "starfield/Config.h" #include "starfield/data/InputVertex.h" #include "starfield/data/BrightnessLevel.h" @@ -66,22 +64,6 @@ namespace starfield { class Renderer { - - GpuVertex* _arrData; - Tile* _arrTile; - GLint* _arrBatchOffs; - GLsizei* _arrBatchCount; - GLuint _hndVertexArray; - ProgramObject _objProgram; - int _alphaLocation; - - Tiling _objTiling; - - unsigned* _itrOutIndex; - vec3 _vecWxform; - float _valHalfPersp; - BrightnessLevel _valMinBright; - public: Renderer(InputVertices const& src, @@ -90,9 +72,9 @@ namespace starfield { BrightnessLevel b, BrightnessLevel bMin) : - _arrData(0l), - _arrTile(0l), - _objTiling(k) { + _dataArray(0l), + _tileArray(0l), + _tiling(k) { this->glAlloc(); @@ -103,10 +85,10 @@ namespace starfield { // REVISIT: batch arrays are probably oversized, but - hey - they // are not very large (unless for insane tiling) and we're better // off safe than sorry - _arrData = new GpuVertex[n]; - _arrTile = new Tile[nTiles + 1]; - _arrBatchOffs = new GLint[nTiles * 2]; - _arrBatchCount = new GLsizei[nTiles * 2]; + _dataArray = new GpuVertex[n]; + _tileArray = new Tile[nTiles + 1]; + _batchOffs = new GLint[nTiles * 2]; + _batchCountArray = new GLsizei[nTiles * 2]; prepareVertexData(src, n, tiling, b, bMin); @@ -115,10 +97,10 @@ namespace starfield { ~Renderer() { - delete[] _arrData; - delete[] _arrTile; - delete[] _arrBatchCount; - delete[] _arrBatchOffs; + delete[] _dataArray; + delete[] _tileArray; + delete[] _batchCountArray; + delete[] _batchOffs; this->glFree(); } @@ -174,30 +156,31 @@ namespace starfield { matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f) * glm::affineInverse(matrix); - this->_itrOutIndex = (unsigned*) _arrBatchOffs; - this->_vecWxform = vec3(row(matrix, 3)); - this->_valHalfPersp = halfPersp; - this->_valMinBright = minBright; + this->_outIndexPos = (unsigned*) _batchOffs; + this->_wRowVec = vec3(row(matrix, 3)); + this->_halfPerspectiveAngle = halfPersp; + this->_minBright = minBright; TileSelection::Cursor cursor; - cursor.current = _arrTile + _objTiling.getTileIndex(azimuth, altitude); - cursor.firstInRow = _arrTile + _objTiling.getTileIndex(0.0f, altitude); + cursor.current = _tileArray + _tiling.getTileIndex(azimuth, altitude); + cursor.firstInRow = _tileArray + _tiling.getTileIndex(0.0f, altitude); - floodFill(cursor, TileSelection(*this, _arrTile, _arrTile + _objTiling.getTileCount(), - (TileSelection::Cursor*) _arrBatchCount)); + floodFill(cursor, TileSelection(*this, _tileArray, _tileArray + _tiling.getTileCount(), + (TileSelection::Cursor*) _batchCountArray)); #if STARFIELD_DEBUG_CULLING # define matrix matrix_debug #endif this->glBatch(glm::value_ptr(matrix), prepareBatch( - (unsigned*) _arrBatchOffs, _itrOutIndex), alpha); + (unsigned*) _batchOffs, _outIndexPos), alpha); #if STARFIELD_DEBUG_CULLING # undef matrix #endif } - private: // renderer construction + private: + // renderer construction void prepareVertexData(InputVertices const& src, size_t n, // <-- at bMin and brighter @@ -208,9 +191,9 @@ namespace starfield { size_t nTiles = tiling.getTileCount(); size_t vertexIndex = 0u, currTileIndex = 0u, count_active = 0u; - _arrTile[0].offset = 0u; - _arrTile[0].lod = b; - _arrTile[0].flags = 0u; + _tileArray[0].offset = 0u; + _tileArray[0].lod = b; + _tileArray[0].flags = 0u; for (InputVertices::const_iterator i = src.begin(), e = src.end(); i != e; ++i) { @@ -227,8 +210,8 @@ namespace starfield { // moved on to another tile? -> flush if (tileIndex != currTileIndex) { - Tile* t = _arrTile + currTileIndex; - Tile* tLast = _arrTile + tileIndex; + Tile* t = _tileArray + currTileIndex; + Tile* tLast = _tileArray + tileIndex; // set count of active vertices (upcoming lod) t->count = count_active; @@ -253,21 +236,20 @@ namespace starfield { // printLog("Stars.cpp: Vertex %d on tile #%d\n", vertexIndex, tileIndex); // write converted vertex - _arrData[vertexIndex++] = *i; + _dataArray[vertexIndex++] = *i; } } assert(vertexIndex == n); // flush last tile (see above) - Tile* t = _arrTile + currTileIndex; + Tile* t = _tileArray + currTileIndex; t->count = count_active; - for (Tile* e = _arrTile + nTiles + 1; ++t != e;) { + for (Tile* e = _tileArray + nTiles + 1; ++t != e;) { t->offset = vertexIndex, t->count = 0u, t->lod = b, t->flags = 0; } } - - private: // FOV culling / LOD + // FOV culling / LOD class TileSelection; friend class Renderer::TileSelection; @@ -277,22 +259,22 @@ namespace starfield { public: struct Cursor { Tile* current, * firstInRow; }; private: - Renderer& _refRenderer; - Cursor* const _arrStack; - Cursor* _itrStack; - Tile const* const _arrTile; - Tile const* const _ptrTilesEnd; + Renderer& _rendererRef; + Cursor* const _stackArray; + Cursor* _stackPos; + Tile const* const _tileArray; + Tile const* const _tilesEnd; public: TileSelection(Renderer& renderer, Tile const* tiles, Tile const* tiles_end, Cursor* stack) : - _refRenderer(renderer), - _arrStack(stack), - _itrStack(stack), - _arrTile(tiles), - _ptrTilesEnd(tiles_end) { + _rendererRef(renderer), + _stackArray(stack), + _stackPos(stack), + _tileArray(tiles), + _tilesEnd(tiles_end) { } protected: @@ -302,7 +284,7 @@ namespace starfield { bool select(Cursor const& c) { Tile* t = c.current; - if (t < _arrTile || t >= _ptrTilesEnd || + if (t < _tileArray || t >= _tilesEnd || !! (t->flags & Tile::checked)) { // out of bounds or been here already @@ -311,7 +293,7 @@ namespace starfield { // will check now and never again t->flags |= Tile::checked; - if (_refRenderer.visitTile(t)) { + if (_rendererRef.visitTile(t)) { // good one -> remember (for batching) and propagate t->flags |= Tile::render; @@ -334,39 +316,39 @@ namespace starfield { void right(Cursor& c) const { c.current += 1; - if (c.current == c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles()) { + if (c.current == c.firstInRow + _rendererRef._tiling.getAzimuthalTiles()) { c.current = c.firstInRow; } } void left(Cursor& c) const { if (c.current == c.firstInRow) { - c.current = c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles(); + c.current = c.firstInRow + _rendererRef._tiling.getAzimuthalTiles(); } c.current -= 1; } void up(Cursor& c) const { - unsigned d = _refRenderer._objTiling.getAzimuthalTiles(); + unsigned d = _rendererRef._tiling.getAzimuthalTiles(); c.current += d; c.firstInRow += d; } void down(Cursor& c) const { - unsigned d = _refRenderer._objTiling.getAzimuthalTiles(); + unsigned d = _rendererRef._tiling.getAzimuthalTiles(); c.current -= d; c.firstInRow -= d; } void defer(Cursor const& t) { - *_itrStack++ = t; + *_stackPos++ = t; } bool deferred(Cursor& cursor) { - if (_itrStack != _arrStack) { - cursor = *--_itrStack; + if (_stackPos != _stackArray) { + cursor = *--_stackPos; return true; } return false; @@ -375,35 +357,35 @@ namespace starfield { bool visitTile(Tile* t) { - unsigned index = t - _arrTile; - *_itrOutIndex++ = index; + unsigned index = t - _tileArray; + *_outIndexPos++ = index; if (! tileVisible(t, index)) { return false; } - if (t->lod != _valMinBright) { - updateVertexCount(t, _valMinBright); + if (t->lod != _minBright) { + updateVertexCount(t, _minBright); } return true; } bool tileVisible(Tile* t, unsigned i) { - float slice = _objTiling.getSliceAngle(); + float slice = _tiling.getSliceAngle(); float halfSlice = 0.5f * slice; - unsigned stride = _objTiling.getAzimuthalTiles(); + unsigned stride = _tiling.getAzimuthalTiles(); float azimuth = (i % stride) * slice; float altitude = (i / stride) * slice - Radians::halfPi(); float gx = sin(azimuth); float gz = -cos(azimuth); float exz = cos(altitude); vec3 tileCenter = vec3(gx * exz, sin(altitude), gz * exz); - float w = dot(_vecWxform, tileCenter); + float w = dot(_wRowVec, tileCenter); float daz = halfSlice * cos(std::max(0.0f, abs(altitude) - halfSlice)); float dal = halfSlice; - float adjustedNear = cos(_valHalfPersp + sqrt(daz * daz + dal * dal)); + float adjustedNear = cos(_halfPerspectiveAngle + sqrt(daz * daz + dal * dal)); // printLog("Stars.cpp: checking tile #%d, w = %f, near = %f\n", i, w, nearClip); @@ -417,8 +399,8 @@ namespace starfield { // perform a binary search in the so found partition for the // new vertex count of this tile - GpuVertex const* start = _arrData + t[0].offset; - GpuVertex const* end = _arrData + t[1].offset; + GpuVertex const* start = _dataArray + t[0].offset; + GpuVertex const* end = _dataArray + t[1].offset; assert(end >= start); @@ -433,9 +415,9 @@ namespace starfield { end = std::upper_bound( start, end, minBright, GreaterBrightness()); - assert(end >= _arrData + t[0].offset); + assert(end >= _dataArray + t[0].offset); - t->count = end - _arrData - t[0].offset; + t->count = end - _dataArray - t[0].offset; t->lod = minBright; } @@ -443,13 +425,13 @@ namespace starfield { unsigned const* indicesEnd) { unsigned nRanges = 0u; - GLint* offs = _arrBatchOffs; - GLsizei* count = _arrBatchCount; + GLint* offs = _batchOffs; + GLsizei* count = _batchCountArray; - for (unsigned* i = (unsigned*) _arrBatchOffs; + for (unsigned* i = (unsigned*) _batchOffs; i != indicesEnd; ++i) { - Tile* t = _arrTile + *i; + Tile* t = _tileArray + *i; if ((t->flags & Tile::render) > 0u && t->count > 0u) { *offs++ = t->offset; @@ -461,7 +443,7 @@ namespace starfield { return nRanges; } - private: // gl API handling + // GL API handling void glAlloc() { @@ -478,28 +460,28 @@ namespace starfield { " gl_PointSize = s;\n" "}\n"; - _objProgram.addShaderFromSourceCode(QGLShader::Vertex, VERTEX_SHADER); + _program.addShaderFromSourceCode(QGLShader::Vertex, VERTEX_SHADER); GLchar const* const FRAGMENT_SHADER = "#version 120\n" "void main(void) {\n" " gl_FragColor = gl_Color;\n" "}\n"; - _objProgram.addShaderFromSourceCode(QGLShader::Fragment, FRAGMENT_SHADER); - _objProgram.link(); - _alphaLocation = _objProgram.uniformLocation("alpha"); + _program.addShaderFromSourceCode(QGLShader::Fragment, FRAGMENT_SHADER); + _program.link(); + _alphaLocationHandle = _program.uniformLocation("alpha"); - glGenBuffersARB(1, & _hndVertexArray); + glGenBuffersARB(1, & _vertexArrayHandle); } void glFree() { - glDeleteBuffersARB(1, & _hndVertexArray); + glDeleteBuffersARB(1, & _vertexArrayHandle); } void glUpload(GLsizei n) { - glBindBufferARB(GL_ARRAY_BUFFER, _hndVertexArray); + glBindBufferARB(GL_ARRAY_BUFFER, _vertexArrayHandle); glBufferData(GL_ARRAY_BUFFER, - n * sizeof(GpuVertex), _arrData, GL_STATIC_DRAW); + n * sizeof(GpuVertex), _dataArray, GL_STATIC_DRAW); //glInterleavedArrays(GL_C4UB_V3F, sizeof(GpuVertex), 0l); glBindBufferARB(GL_ARRAY_BUFFER, 0); @@ -511,7 +493,7 @@ namespace starfield { // for (int i = 0; i < n_ranges; ++i) // printLog("Stars.cpp: Batch #%d - %d stars @ %d\n", i, -// _arrBatchOffs[i], _arrBatchCount[i]); +// _batchOffs[i], _batchCountArray[i]); glDisable(GL_DEPTH_TEST); glDisable(GL_LIGHTING); @@ -533,24 +515,42 @@ namespace starfield { glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); // select shader and vertex array - _objProgram.bind(); - _objProgram.setUniformValue(_alphaLocation, alpha); - glBindBufferARB(GL_ARRAY_BUFFER, _hndVertexArray); + _program.bind(); + _program.setUniformValue(_alphaLocationHandle, alpha); + glBindBufferARB(GL_ARRAY_BUFFER, _vertexArrayHandle); glInterleavedArrays(GL_C4UB_V3F, sizeof(GpuVertex), 0l); // render glMultiDrawArrays(GL_POINTS, - _arrBatchOffs, _arrBatchCount, n_ranges); + _batchOffs, _batchCountArray, n_ranges); // restore state glBindBufferARB(GL_ARRAY_BUFFER, 0); - _objProgram.release(); + _program.release(); glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); glDisable(GL_POINT_SMOOTH); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); } + + // variables + + GpuVertex* _dataArray; + Tile* _tileArray; + GLint* _batchOffs; + GLsizei* _batchCountArray; + GLuint _vertexArrayHandle; + ProgramObject _program; + int _alphaLocationHandle; + + Tiling _tiling; + + unsigned* _outIndexPos; + vec3 _wRowVec; + float _halfPerspectiveAngle; + BrightnessLevel _minBright; + }; } // anonymous namespace diff --git a/interface/src/starfield/renderer/Tiling.h b/interface/src/starfield/renderer/Tiling.h index 56df23f30c..fdec54dfc7 100644 --- a/interface/src/starfield/renderer/Tiling.h +++ b/interface/src/starfield/renderer/Tiling.h @@ -18,22 +18,17 @@ namespace starfield { class Tiling { - - unsigned _valK; - float _valRcpSlice; - unsigned _valBits; - public: Tiling(unsigned k) : _valK(k), - _valRcpSlice(k / Radians::twicePi()) { - _valBits = ceil(log(getTileCount()) * 1.4426950408889634); // log2 + _rcpSlice(k / Radians::twicePi()) { + _nBits = ceil(log(getTileCount()) * 1.4426950408889634); // log2 } unsigned getAzimuthalTiles() const { return _valK; } unsigned getAltitudinalTiles() const { return _valK / 2 + 1; } - unsigned getTileIndexBits() const { return _valBits; } + unsigned getTileIndexBits() const { return _nBits; } unsigned getTileCount() const { return getAzimuthalTiles() * getAltitudinalTiles(); @@ -45,14 +40,14 @@ namespace starfield { } float getSliceAngle() const { - return 1.0f / _valRcpSlice; + return 1.0f / _rcpSlice; } private: unsigned discreteAngle(float unsigned_angle) const { - return unsigned(floor(unsigned_angle * _valRcpSlice + 0.5f)); + return unsigned(floor(unsigned_angle * _rcpSlice + 0.5f)); } unsigned discreteAzimuth(float a) const { @@ -64,6 +59,11 @@ namespace starfield { discreteAngle(a + Radians::halfPi()) ); } + // variables + + unsigned _valK; + float _rcpSlice; + unsigned _nBits; }; } // anonymous namespace diff --git a/interface/src/starfield/renderer/VertexOrder.h b/interface/src/starfield/renderer/VertexOrder.h index 13784de53e..d74864af18 100644 --- a/interface/src/starfield/renderer/VertexOrder.h +++ b/interface/src/starfield/renderer/VertexOrder.h @@ -25,25 +25,26 @@ namespace starfield { */ class VertexOrder : public Radix2IntegerScanner { - Tiling _objTiling; - - typedef Radix2IntegerScanner base; public: - explicit VertexOrder(Tiling const& tiling) : base(tiling.getTileIndexBits() + BrightnessBits), - _objTiling(tiling) { + _tiling(tiling) { } bool bit(InputVertex const& v, state_type const& s) const { // inspect (tile_index, brightness) tuples unsigned key = getBrightness(v.getColor()) ^ BrightnessMask; - key |= _objTiling.getTileIndex( + key |= _tiling.getTileIndex( v.getAzimuth(), v.getAltitude()) << BrightnessBits; return base::bit(key, s); } + + private: + Tiling _tiling; + + typedef Radix2IntegerScanner base; }; } // anonymous namespace diff --git a/interface/src/ui/TextRenderer.h b/interface/src/ui/TextRenderer.h index 643c3ede8c..ff484066d8 100644 --- a/interface/src/ui/TextRenderer.h +++ b/interface/src/ui/TextRenderer.h @@ -15,6 +15,8 @@ #include #include +#include "InterfaceConfig.h" + // a special "character" that renders as a solid block const char SOLID_BLOCK_CHAR = 127; diff --git a/libraries/avatars/src/AvatarData.cpp b/libraries/avatars/src/AvatarData.cpp index 820626d369..498e43cc28 100644 --- a/libraries/avatars/src/AvatarData.cpp +++ b/libraries/avatars/src/AvatarData.cpp @@ -14,10 +14,8 @@ #include #include "AvatarData.h" -#include "avatars_Log.h" using namespace std; -using avatars_lib::printLog; int packFloatAngleToTwoByte(unsigned char* buffer, float angle) { const float ANGLE_CONVERSION_RATIO = (std::numeric_limits::max() / 360.0); @@ -236,4 +234,4 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) { _wantDelta = oneAtBit(wantItems,WANT_DELTA_AT_BIT); return sourceBuffer - startPosition; -} \ No newline at end of file +} diff --git a/libraries/avatars/src/Orientation.cpp b/libraries/avatars/src/Orientation.cpp index 6466eb802c..1d26e99e49 100755 --- a/libraries/avatars/src/Orientation.cpp +++ b/libraries/avatars/src/Orientation.cpp @@ -7,9 +7,6 @@ #include "Orientation.h" #include "SharedUtil.h" -//#include "avatars_Log.h" - -//using avatars_lib::printLog; static const bool USING_QUATERNIONS = true; diff --git a/libraries/avatars/src/avatars_Log.cpp b/libraries/avatars/src/avatars_Log.cpp deleted file mode 100644 index da8712b755..0000000000 --- a/libraries/avatars/src/avatars_Log.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// -// avatars_Log.cpp -// hifi -// -// Created by Tobias Schwinger on 4/17/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include "shared_Log.h" - -#include - -namespace avatars_lib { - using namespace std; - - int (* printLog)(char const*, ...) = & printf; -} diff --git a/libraries/avatars/src/avatars_Log.h b/libraries/avatars/src/avatars_Log.h deleted file mode 100644 index 1d07cf46bf..0000000000 --- a/libraries/avatars/src/avatars_Log.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// avatars_Log.h -// hifi -// -// Created by Tobias Schwinger on 4/17/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __hifi__avatars_Log__ -#define __hifi__avatars_Log__ - -namespace avatars_lib { - - // variable that can be set from outside to redirect the log output - // of this library - extern int (* printLog)(char const*, ...); -} - -#endif /* defined(__hifi__avatars_Log__) */ - diff --git a/libraries/shared/src/Agent.cpp b/libraries/shared/src/Agent.cpp index f21f06eba6..9bddd45b84 100644 --- a/libraries/shared/src/Agent.cpp +++ b/libraries/shared/src/Agent.cpp @@ -10,7 +10,7 @@ #include "Agent.h" #include "AgentTypes.h" #include -#include "shared_Log.h" +#include "Log.h" #include "UDPSocket.h" #include "SharedUtil.h" @@ -20,8 +20,6 @@ #include #endif -using shared_lib::printLog; - int unpackAgentId(unsigned char* packedData, uint16_t* agentId) { memcpy(agentId, packedData, sizeof(uint16_t)); return sizeof(uint16_t); @@ -150,4 +148,4 @@ void Agent::printLog(Agent const& agent) { agent._type, publicAddressBuffer, publicAddressPort); -} \ No newline at end of file +} diff --git a/libraries/shared/src/AgentList.cpp b/libraries/shared/src/AgentList.cpp index 8f97135eab..170b86147b 100644 --- a/libraries/shared/src/AgentList.cpp +++ b/libraries/shared/src/AgentList.cpp @@ -15,7 +15,7 @@ #include "AgentTypes.h" #include "PacketHeaders.h" #include "SharedUtil.h" -#include "shared_Log.h" +#include "Log.h" #ifdef _WIN32 #include "Syssocket.h" @@ -23,8 +23,6 @@ #include #endif -using shared_lib::printLog; - const char SOLO_AGENT_TYPES[3] = { AGENT_TYPE_AVATAR_MIXER, AGENT_TYPE_AUDIO_MIXER, diff --git a/libraries/voxels/src/voxels_Log.cpp b/libraries/shared/src/Log.cpp similarity index 50% rename from libraries/voxels/src/voxels_Log.cpp rename to libraries/shared/src/Log.cpp index 6fd637a1ec..2db1ab4288 100644 --- a/libraries/voxels/src/voxels_Log.cpp +++ b/libraries/shared/src/Log.cpp @@ -1,17 +1,15 @@ // -// voxels_Log.cpp +// Log.cpp // hifi // // Created by Tobias Schwinger on 4/17/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // -#include "voxels_Log.h" +#include "Log.h" #include -namespace voxels_lib { - using namespace std; +using namespace std; +int (* printLog)(char const*, ...) = & printf; - int (* printLog)(char const*, ...) = & printf; -} diff --git a/libraries/shared/src/shared_Log.h b/libraries/shared/src/Log.h similarity index 50% rename from libraries/shared/src/shared_Log.h rename to libraries/shared/src/Log.h index 29c1a4ed57..e2bc77e1e8 100644 --- a/libraries/shared/src/shared_Log.h +++ b/libraries/shared/src/Log.h @@ -1,5 +1,5 @@ // -// shared_Log.h +// Log.h // hifi // // Created by Tobias Schwinger on 4/17/13. @@ -9,12 +9,13 @@ #ifndef __hifi__shared_Log__ #define __hifi__shared_Log__ -namespace shared_lib { - - // variable that can be set from outside to redirect the log output - // of this library - extern int (* printLog)(char const*, ...); -} +// +// Pointer to log function +// +// An application may reset this variable to receive the log messages +// issued using 'printLog'. It defaults to a pointer to 'printf'. +// +extern int (* printLog)(char const*, ...); #endif /* defined(__hifi__shared_Log__) */ diff --git a/libraries/shared/src/OctalCode.cpp b/libraries/shared/src/OctalCode.cpp index da2b017875..d218639882 100644 --- a/libraries/shared/src/OctalCode.cpp +++ b/libraries/shared/src/OctalCode.cpp @@ -11,9 +11,7 @@ #include #include "SharedUtil.h" #include "OctalCode.h" -#include "shared_Log.h" - -using shared_lib::printLog; +#include "Log.h" int numberOfThreeBitSectionsInCode(unsigned char * octalCode) { if (*octalCode == 255) { diff --git a/libraries/shared/src/PerfStat.cpp b/libraries/shared/src/PerfStat.cpp index 87998599aa..3c30c62993 100644 --- a/libraries/shared/src/PerfStat.cpp +++ b/libraries/shared/src/PerfStat.cpp @@ -14,9 +14,7 @@ #include #include -#include "shared_Log.h" - -using shared_lib::printLog; +#include "Log.h" // Static class members initialization here! std::map > PerfStat::groupHistoryMap; diff --git a/libraries/shared/src/SharedUtil.cpp b/libraries/shared/src/SharedUtil.cpp index 113b3fdda0..6e23413ea7 100644 --- a/libraries/shared/src/SharedUtil.cpp +++ b/libraries/shared/src/SharedUtil.cpp @@ -14,7 +14,7 @@ #ifdef _WIN32 #include "Syssocket.h" #endif -#include "shared_Log.h" +#include "Log.h" #include "SharedUtil.h" #include "OctalCode.h" @@ -22,8 +22,6 @@ #include #endif -using shared_lib::printLog; - double usecTimestamp(timeval *time) { return (time->tv_sec * 1000000.0 + time->tv_usec); } diff --git a/libraries/shared/src/UDPSocket.cpp b/libraries/shared/src/UDPSocket.cpp index 88930d4af4..48fc18ef04 100644 --- a/libraries/shared/src/UDPSocket.cpp +++ b/libraries/shared/src/UDPSocket.cpp @@ -21,9 +21,7 @@ #include #endif -#include "shared_Log.h" - -using shared_lib::printLog; +#include "Log.h" sockaddr_in destSockaddr, senderAddress; diff --git a/libraries/shared/src/UrlReader.cpp b/libraries/shared/src/UrlReader.cpp index 8814de899a..638134f4dd 100644 --- a/libraries/shared/src/UrlReader.cpp +++ b/libraries/shared/src/UrlReader.cpp @@ -10,121 +10,166 @@ #include -#ifdef _WIN32 -#define NOCURL_IN_WINDOWS -#endif - #include #include -#ifndef NOCURL_IN_WINDOWS -#include -size_t const UrlReader::max_read_ahead = CURL_MAX_WRITE_SIZE; -#else -size_t const UrlReader::max_read_ahead = 0; -#endif +#include "Log.h" -char const* const UrlReader::success = "UrlReader: Success!"; -char const* const UrlReader::success_cached = "UrlReader:: Using local file."; +#ifndef _WIN32 +// (Windows port is incomplete and the build files do not support CURL, yet) + +#include + + +// +// ATTENTION: A certain part of the implementation lives in inlined code +// (see the bottom of the header file). +// +// Why? Because it allows stream parsing without having to call around a +// lot (one static and one dynamic call per character if the parser just +// reads one character at a time). +// +// Here is an overview of the code structure: +// +// readUrl +// -> transferBegin (sets up state) +// -> perform (starts CURL transfer) +// -> (specialized, type-erased) callback_template +// -> getInfo (fetches HTTP header, eventually initiates caching) +// -> stream.begin (client code - called once) +// -> feedBuffered (the buffering logic) +// -> stream.transfer (client code - called repeatedly) +// -> stream.end (client code - called when the transfer is done) +// -> transferEnd (closes cache file, if used) +// +// "->" means "calls or inlines", here +// + +size_t const UrlReader::max_read_ahead = CURL_MAX_WRITE_SIZE; + +char const* const UrlReader::success = "UrlReader: Success!"; +char const* const UrlReader::success_cached = "UrlReader: Using local file."; char const* const UrlReader::error_init_failed = "UrlReader: Initialization failed."; char const* const UrlReader::error_aborted = "UrlReader: Processing error."; char const* const UrlReader::error_buffer_overflow = "UrlReader: Buffer overflow."; char const* const UrlReader::error_leftover_input = "UrlReader: Incomplete processing."; -#define hnd_curl static_cast(_ptrImpl) +#define _curlPtr static_cast(_curlHandle) UrlReader::UrlReader() - : _ptrImpl(0l), _arrXtra(0l), _strError(0l), _arrCacheRdBuf(0l) { + : _curlHandle(0l), _xtraBuffer(0l), _errorStr(0l), _cacheReadBuffer(0l) { - _arrXtra = new(std::nothrow) char[max_read_ahead]; - if (! _arrXtra) { _strError = error_init_failed; return; } -#ifndef NOCURL_IN_WINDOWS - _ptrImpl = curl_easy_init(); - if (! _ptrImpl) { _strError = error_init_failed; return; } - curl_easy_setopt(hnd_curl, CURLOPT_NOSIGNAL, 1l); - curl_easy_setopt(hnd_curl, CURLOPT_FAILONERROR, 1l); - curl_easy_setopt(hnd_curl, CURLOPT_FILETIME, 1l); - curl_easy_setopt(hnd_curl, CURLOPT_ENCODING, ""); -#endif + _xtraBuffer = new(std::nothrow) char[max_read_ahead]; + if (! _xtraBuffer) { _errorStr = error_init_failed; return; } + _curlHandle = curl_easy_init(); + if (! _curlHandle) { _errorStr = error_init_failed; return; } + curl_easy_setopt(_curlPtr, CURLOPT_NOSIGNAL, 1l); + curl_easy_setopt(_curlPtr, CURLOPT_FAILONERROR, 1l); + curl_easy_setopt(_curlPtr, CURLOPT_FILETIME, 1l); + curl_easy_setopt(_curlPtr, CURLOPT_ENCODING, ""); } UrlReader::~UrlReader() { - delete[] _arrXtra; - delete[] _arrCacheRdBuf; -#ifndef NOCURL_IN_WINDOWS - if (! hnd_curl) return; - curl_easy_cleanup(hnd_curl); -#endif + delete[] _xtraBuffer; + delete[] _cacheReadBuffer; + if (! _curlHandle) { + return; + } + curl_easy_cleanup(_curlPtr); } -bool UrlReader::perform(char const* url, transfer_callback* cb) { -#ifndef NOCURL_IN_WINDOWS +void UrlReader::perform(char const* url, transfer_callback* cb) { - curl_easy_setopt(hnd_curl, CURLOPT_URL, url); - curl_easy_setopt(hnd_curl, CURLOPT_WRITEFUNCTION, cb); - curl_easy_setopt(hnd_curl, CURLOPT_WRITEDATA, this); + curl_easy_setopt(_curlPtr, CURLOPT_URL, url); + curl_easy_setopt(_curlPtr, CURLOPT_WRITEFUNCTION, cb); + curl_easy_setopt(_curlPtr, CURLOPT_WRITEDATA, this); - CURLcode rc = curl_easy_perform(hnd_curl); + CURLcode rc = curl_easy_perform(_curlPtr); if (rc == CURLE_OK) { - while (_valXtraSize > 0 && _strError == success) + while (_xtraSize > 0 && _errorStr == success) cb(0l, 0, 0, this); } - else if (_strError == success) - _strError = curl_easy_strerror(rc); - - return rc == CURLE_OK; -#else - return false; -#endif + else if (_errorStr == success) + _errorStr = curl_easy_strerror(rc); } -void UrlReader::getinfo(char const*& url, - char const*& type, int64_t& length, int64_t& stardate) { -#ifndef NOCURL_IN_WINDOWS +void UrlReader::transferBegin(void* stream, char const* cacheFile) { + _errorStr = success; + _streamPtr = stream; + _cacheFileName = cacheFile; + _cacheFile = 0l; + _cacheMode = no_cache; + _xtraSize = ~size_t(0); +} + +void UrlReader::getInfo(char const*& url, + char const*& type, int64_t& length, int64_t& stardate) { + + // fetch information from HTTP header double clen; long time; - curl_easy_getinfo(hnd_curl, CURLINFO_FILETIME, & time); + curl_easy_getinfo(_curlPtr, CURLINFO_FILETIME, & time); + curl_easy_getinfo(_curlPtr, CURLINFO_EFFECTIVE_URL, & url); + curl_easy_getinfo(_curlPtr, CURLINFO_CONTENT_TYPE, & type); + curl_easy_getinfo(_curlPtr, CURLINFO_CONTENT_LENGTH_DOWNLOAD, & clen); + length = static_cast(clen); + curl_easy_getinfo(_curlPtr, CURLINFO_FILETIME, & time); + stardate = time; + +// printLog("UrlReader: Ready to transfer from URL '%s'\n", url); // check caching file time whether we actually want to download anything - if (_strCacheFile != 0l) { + if (_cacheFileName != 0l) { struct stat s; - stat(_strCacheFile, & s); + stat(_cacheFileName, & s); if (time > s.st_mtime) { // file on server is newer -> update cache file - _ptrCacheFile = fopen(_strCacheFile, "wb"); - printf("From URL: "); - if (_ptrCacheFile != 0l) { - _valCacheMode = cache_write; + _cacheFile = fopen(_cacheFileName, "wb"); +// printLog("UrlReader: Also writing content to cache file '%s'\n", _cacheFileName); + if (_cacheFile != 0l) { + _cacheMode = cache_write; } } else { // file on server is older -> use cache file - if (! _arrCacheRdBuf) { - _arrCacheRdBuf = new (std::nothrow) char[max_read_ahead]; - if (! _arrCacheRdBuf) { - _valCacheMode = no_cache; + if (! _cacheReadBuffer) { + _cacheReadBuffer = new (std::nothrow) char[max_read_ahead]; + if (! _cacheReadBuffer) { + // out of memory, no caching, have CURL catch it + return; } } - _ptrCacheFile = fopen(_strCacheFile, "rb"); - printf("From file: "); - if (_ptrCacheFile != 0l) { - _valCacheMode = cache_read; + _cacheFile = fopen(_cacheFileName, "rb"); +// printLog("UrlReader: Delivering cached content from file '%s'\n", _cacheFileName); + if (_cacheFile != 0l) { + _cacheMode = cache_read; } - _strError = success_cached; + // override error code returned by CURL when we abort the download + _errorStr = success_cached; } } - - curl_easy_getinfo(hnd_curl, CURLINFO_EFFECTIVE_URL, & url); - curl_easy_getinfo(hnd_curl, CURLINFO_CONTENT_TYPE, & type); - - curl_easy_getinfo(hnd_curl, CURLINFO_CONTENT_LENGTH_DOWNLOAD, & clen); - length = static_cast(clen); - - curl_easy_getinfo(hnd_curl, CURLINFO_FILETIME, & time); - stardate = time; -#endif } +void UrlReader::transferEnd() { + + if (_cacheFile != 0l) { + fclose(_cacheFile); + } +} + +#else // no-op version for incomplete Windows build: + +UrlReader::UrlReader() : _curlHandle(0l) { } +UrlReader::~UrlReader() { } +void UrlReader::perform(char const* url, transfer_callback* cb) { } +void UrlReader::transferBegin(void* stream, char const* cacheFile) { } +void UrlReader::getInfo(char const*& url, char const*& type, + int64_t& length, int64_t& stardate) { } +void UrlReader::transferEnd() { } + +#endif + + diff --git a/libraries/shared/src/UrlReader.h b/libraries/shared/src/UrlReader.h index 9ad77d27ff..8a9084ce32 100644 --- a/libraries/shared/src/UrlReader.h +++ b/libraries/shared/src/UrlReader.h @@ -19,177 +19,190 @@ // via URLs. Use one per thread. // class UrlReader { +public: - enum CacheMode { no_cache, cache_write, cache_read }; + // + // Constructor - performs initialization, never throws. + // + UrlReader(); - void* _ptrImpl; - char* _arrXtra; - char const* _strError; - void* _ptrStream; - char const* _strCacheFile; - FILE* _ptrCacheFile; - char* _arrCacheRdBuf; - CacheMode _valCacheMode; - size_t _valXtraSize; - public: + // + // Destructor - frees resources, never throws. + // + ~UrlReader(); - // - // Constructor - performs initialization, never throws. - // - UrlReader(); + // + // Reads data from an URL and forwards it to the instance of a class + // fulfilling the ContentStream concept. + // + // The call protocol on the ContentStream is detailed as follows: + // + // 1. begin(char const* url, + // char const* content_type, uint64_t bytes, uint64_t stardate) + // + // All information except 'url' is optional; 'content_type' can + // be a null pointer - 'bytes' and 'stardate' can be equal to + // to 'unavailable'. + // + // 2. transfer(char* buffer, size_t bytes) + // + // Called until all data has been received. The number of bytes + // actually processed should be returned. + // Unprocessed data is stored in an extra buffer whose size is + // given by the constant UrlReader::max_read_ahead - it can be + // assumed to be reasonably large for on-the-fly parsing. + // + // 3. end(bool ok) + // + // Called at the end of the transfer. + // + // Returns the same success code + // + template< class ContentStream > + bool readUrl(char const* url, ContentStream& s, char const* cacheFile = 0l); - // - // Destructor - frees resources, never throws. - // - ~UrlReader(); + // + // Returns a pointer to a static C-string that describes the error + // condition. + // + inline char const* getError() const; - // - // Reads data from an URL and forwards it to the instance of a class - // fulfilling the ContentStream concept. - // - // The call protocol on the ContentStream is detailed as follows: - // - // 1. begin(char const* url, - // char const* content_type, uint64_t bytes, uint64_t stardate) - // - // All information except 'url' is optional; 'content_type' can - // be a null pointer - 'bytes' and 'stardate' can be equal to - // to 'unavailable'. - // - // 2. transfer(char* buffer, size_t bytes) - // - // Called until all data has been received. The number of bytes - // actually processed should be returned. - // Unprocessed data is stored in an extra buffer whose size is - // given by the constant UrlReader::max_read_ahead - it can be - // assumed to be reasonably large for on-the-fly parsing. - // - // 3. end(bool ok) - // - // Called at the end of the transfer. - // - // Returns the same success code - // - template< class ContentStream > - bool readUrl(char const* url, ContentStream& s, char const* cacheFile = 0l); + // + // Can be called by the stream to set a user-defined error string. + // + inline void setError(char const* static_c_string); - // - // Returns a pointer to a static C-string that describes the error - // condition. - // - inline char const* getError() const; + // + // Pointer to the C-string returned by a call to 'readUrl' when no + // error occurred. + // + static char const* const success; - // - // Can be called by the stream to set a user-defined error string. - // - inline void setError(char const* static_c_string); + // + // Pointer to the C-string returned by a call to 'readUrl' when no + // error occurred and a local file has been read instead of the + // network stream. + // + static char const* const success_cached; - // - // Pointer to the C-string returned by a call to 'readUrl' when no - // error occurred. - // - static char const* const success; + // + // Pointer to the C-string returned by a call to 'readUrl' when the + // initialization has failed. + // + static char const* const error_init_failed; - // - // Pointer to the C-string returned by a call to 'readUrl' when no - // error occurred and a local file has been read instead of the - // network stream. - // - static char const* const success_cached; - - // - // Pointer to the C-string returned by a call to 'readUrl' when the - // initialization has failed. - // - static char const* const error_init_failed; + // + // Pointer to the C-string returned by a call to 'readUrl' when the + // transfer has been aborted by the client. + // + static char const* const error_aborted; - // - // Pointer to the C-string returned by a call to 'readUrl' when the - // transfer has been aborted by the client. - // - static char const* const error_aborted; + // + // Pointer to the C-string returned by a call to 'readUrl' when + // leftover input from incomplete processing caused a buffer + // overflow. + // + static char const* const error_buffer_overflow; - // - // Pointer to the C-string returned by a call to 'readUrl' when - // leftover input from incomplete processing caused a buffer - // overflow. - // - static char const* const error_buffer_overflow; + // + // Pointer to the C-string return by a call to 'readUrl' when the + // input provided was not completely consumed. + // + static char const* const error_leftover_input; - // - // Pointer to the C-string return by a call to 'readUrl' when the - // input provided was not completely consumed. - // - static char const* const error_leftover_input; + // + // Constant of the maximum number of bytes that are buffered + // between invocations of 'transfer'. + // + static size_t const max_read_ahead; - // - // Constant of the maximum number of bytes that are buffered - // between invocations of 'transfer'. - // - static size_t const max_read_ahead; + // + // Constant representing absent information in the call to the + // 'begin' member function of the target stream. + // + static int const unavailable = -1; - // - // Constant representing absent information in the call to the - // 'begin' member function of the target stream. - // - static int const unavailable = -1; + // + // Constant for requesting to abort the current transfer when + // returned by the 'transfer' member function of the target stream. + // + static size_t const abort = ~0u; - // - // Constant for requesting to abort the current transfer when - // returned by the 'transfer' member function of the target stream. - // - static size_t const abort = ~0u; +private: + // instances of this class shall not be copied + UrlReader(UrlReader const&); // = delete; + UrlReader& operator=(UrlReader const&); // = delete; - private: - // instances of this class shall not be copied - UrlReader(UrlReader const&); // = delete; - UrlReader& operator=(UrlReader const&); // = delete; + inline bool isSuccess(); - // entrypoints to compiled code + // entrypoints to compiled code - typedef size_t transfer_callback(char*, size_t, size_t, void*); + typedef size_t transfer_callback(char*, size_t, size_t, void*); - bool perform(char const* url, transfer_callback* transfer); + enum CacheMode { no_cache, cache_write, cache_read }; - void getinfo(char const*& url, - char const*& type, int64_t& length, int64_t& stardate); + void transferBegin(void* stream, char const* cacheFile); + void transferEnd(); - // synthesized callback + void perform(char const* url, transfer_callback* transfer); - template< class Stream > static size_t callback_template(char *input, size_t size, - size_t nmemb, void* thiz); + void getInfo(char const*& url, + char const*& type, int64_t& length, int64_t& stardate); - template< class Stream > size_t feedBuffered(Stream* stream, - char* input, size_t size); + // synthesized callback + + template< class Stream > static size_t callback_template(char *input, size_t size, + size_t nmemb, void* thiz); + + template< class Stream > size_t feedBuffered(Stream* stream, + char* input, size_t size); + + // state + + void* _curlHandle; + char* _xtraBuffer; + char const* _errorStr; + void* _streamPtr; + char const* _cacheFileName; + FILE* _cacheFile; + char* _cacheReadBuffer; + CacheMode _cacheMode; + size_t _xtraSize; }; +// inline functions + +inline char const* UrlReader::getError() const { + + return _errorStr; +} + +bool UrlReader::isSuccess() { + + return _errorStr == success || _errorStr == success_cached; +} + template< class ContentStream > bool UrlReader::readUrl(char const* url, ContentStream& s, char const* cacheFile) { - if (! _ptrImpl) return false; - _strCacheFile = cacheFile; - _ptrCacheFile = 0l; - _valCacheMode = no_cache; // eventually set later - _strError = success; - _ptrStream = & s; - _valXtraSize = ~size_t(0); - this->perform(url, & callback_template); - s.end(_strError == success); - if (_ptrCacheFile != 0l) { - fclose(_ptrCacheFile); - } - return _strError == success || _strError == success_cached; -} + if (! _curlHandle) return false; -inline char const* UrlReader::getError() const { return this->_strError; } + this->transferBegin(& s, cacheFile); + this->perform(url, & callback_template); + this->transferEnd(); + bool ok = isSuccess(); + s.end(ok); + return ok; +} inline void UrlReader::setError(char const* staticCstring) { - if (this->_strError == success || this->_strError == success_cached) - this->_strError = staticCstring; + if (this->isSuccess()) + this->_errorStr = staticCstring; } template< class Stream > size_t UrlReader::feedBuffered(Stream* stream, char* input, size_t size) { + size_t inputOffset = 0u; while (true) { @@ -198,15 +211,15 @@ size_t UrlReader::feedBuffered(Stream* stream, char* input, size_t size) { size_t bytes = size - inputOffset; // data in extra buffer? - if (_valXtraSize > 0) { + if (_xtraSize > 0) { // fill extra buffer with beginning of input - size_t fill = max_read_ahead - _valXtraSize; + size_t fill = max_read_ahead - _xtraSize; if (bytes < fill) fill = bytes; - memcpy(_arrXtra + _valXtraSize, buffer, fill); + memcpy(_xtraBuffer + _xtraSize, buffer, fill); // use extra buffer for next transfer - buffer = _arrXtra; - bytes = _valXtraSize + fill; + buffer = _xtraBuffer; + bytes = _xtraSize + fill; inputOffset += fill; } @@ -225,9 +238,9 @@ size_t UrlReader::feedBuffered(Stream* stream, char* input, size_t size) { size_t unprocessed = bytes - processed; // can switch to input buffer, now? - if (buffer == _arrXtra && unprocessed <= inputOffset) { + if (buffer == _xtraBuffer && unprocessed <= inputOffset) { - _valXtraSize = 0u; + _xtraSize = 0u; inputOffset -= unprocessed; } else { // no? unprocessed data -> extra buffer @@ -237,10 +250,10 @@ size_t UrlReader::feedBuffered(Stream* stream, char* input, size_t size) { setError(error_buffer_overflow); return 0; } - _valXtraSize = unprocessed; - memmove(_arrXtra, buffer + processed, unprocessed); + _xtraSize = unprocessed; + memmove(_xtraBuffer, buffer + processed, unprocessed); - if (inputOffset == size || buffer != _arrXtra) { + if (inputOffset == size || buffer != _xtraBuffer) { return size; } @@ -253,18 +266,18 @@ size_t UrlReader::callback_template(char *input, size_t size, size_t nmemb, void size_t result = 0u; UrlReader* me = static_cast(thiz); - Stream* stream = static_cast(me->_ptrStream); + Stream* stream = static_cast(me->_streamPtr); size *= nmemb; // first call? - if (me->_valXtraSize == ~size_t(0)) { + if (me->_xtraSize == ~size_t(0)) { - me->_valXtraSize = 0u; + me->_xtraSize = 0u; // extract meta information and call 'begin' char const* url, * type; int64_t length, stardate; - me->getinfo(url, type, length, stardate); - if (me->_valCacheMode != cache_read) { + me->getInfo(url, type, length, stardate); + if (me->_cacheMode != cache_read) { stream->begin(url, type, length, stardate); } } @@ -272,20 +285,20 @@ size_t UrlReader::callback_template(char *input, size_t size, size_t nmemb, void // will have to repeat from here when reading a local file // read from cache file? - if (me->_valCacheMode == cache_read) { + if (me->_cacheMode == cache_read) { // change input buffer and start - input = me->_arrCacheRdBuf; - size = fread(input, 1, max_read_ahead, me->_ptrCacheFile); + input = me->_cacheReadBuffer; + size = fread(input, 1, max_read_ahead, me->_cacheFile); nmemb = 1; - } else if (me->_valCacheMode == cache_write) { - fwrite(input, 1, size, me->_ptrCacheFile); + } else if (me->_cacheMode == cache_write) { + fwrite(input, 1, size, me->_cacheFile); } result = me->feedBuffered(stream, input, size); - } while (me->_valCacheMode == cache_read && result != 0 && ! feof(me->_ptrCacheFile)); + } while (me->_cacheMode == cache_read && result != 0 && ! feof(me->_cacheFile)); - return me->_valCacheMode != cache_read ? result : 0; + return me->_cacheMode != cache_read ? result : 0; } #endif /* defined(__hifi__UrlReader__) */ diff --git a/libraries/shared/src/shared_Log.cpp b/libraries/shared/src/shared_Log.cpp deleted file mode 100644 index 93a5c74714..0000000000 --- a/libraries/shared/src/shared_Log.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// -// shared_Log.cpp -// hifi -// -// Created by Tobias Schwinger on 4/17/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#include "shared_Log.h" - -#include - -namespace shared_lib { - using namespace std; - - int (* printLog)(char const*, ...) = & printf; -} diff --git a/libraries/voxels/src/Plane.cpp b/libraries/voxels/src/Plane.cpp index d999306794..5a99bf29c4 100755 --- a/libraries/voxels/src/Plane.cpp +++ b/libraries/voxels/src/Plane.cpp @@ -9,11 +9,10 @@ // #include "Plane.h" + #include -#include "voxels_Log.h" - -using voxels_lib::printLog; +#include "Log.h" // These are some useful utilities that vec3 is missing void printVec3(const char* name, const glm::vec3& v) { diff --git a/libraries/voxels/src/ViewFrustum.cpp b/libraries/voxels/src/ViewFrustum.cpp index d03678ce42..417c9cc3da 100644 --- a/libraries/voxels/src/ViewFrustum.cpp +++ b/libraries/voxels/src/ViewFrustum.cpp @@ -14,9 +14,8 @@ #include "ViewFrustum.h" #include "SharedUtil.h" -#include "voxels_Log.h" +#include "Log.h" -using voxels_lib::printLog; using namespace std; ViewFrustum::ViewFrustum() : diff --git a/libraries/voxels/src/VoxelNode.cpp b/libraries/voxels/src/VoxelNode.cpp index 5125e2d574..dd6c02c1f3 100644 --- a/libraries/voxels/src/VoxelNode.cpp +++ b/libraries/voxels/src/VoxelNode.cpp @@ -10,14 +10,11 @@ #include #include #include "SharedUtil.h" -#include "voxels_Log.h" +#include "Log.h" #include "VoxelNode.h" #include "VoxelConstants.h" #include "OctalCode.h" #include "AABox.h" -using voxels_lib::printLog; - -// using voxels_lib::printLog; VoxelNode::VoxelNode() { unsigned char* rootCode = new unsigned char[1]; diff --git a/libraries/voxels/src/VoxelTree.cpp b/libraries/voxels/src/VoxelTree.cpp index 4270e90eec..4a20ac160a 100644 --- a/libraries/voxels/src/VoxelTree.cpp +++ b/libraries/voxels/src/VoxelTree.cpp @@ -13,7 +13,7 @@ #include #include #include "SharedUtil.h" -#include "voxels_Log.h" +#include "Log.h" #include "PacketHeaders.h" #include "OctalCode.h" #include "VoxelTree.h" @@ -24,8 +24,6 @@ #include -using voxels_lib::printLog; - int boundaryDistanceForRenderLevel(unsigned int renderLevel) { float voxelSizeScale = 50000.0f; return voxelSizeScale / powf(2, renderLevel); diff --git a/libraries/voxels/src/voxels_Log.h b/libraries/voxels/src/voxels_Log.h deleted file mode 100644 index 3403058a3d..0000000000 --- a/libraries/voxels/src/voxels_Log.h +++ /dev/null @@ -1,20 +0,0 @@ -// -// voxels_Log.h -// hifi -// -// Created by Tobias Schwinger on 4/17/13. -// Copyright (c) 2013 High Fidelity, Inc. All rights reserved. -// - -#ifndef __hifi__voxels_Log__ -#define __hifi__voxels_Log__ - -namespace voxels_lib { - - // variable that can be set from outside to redirect the log output - // of this library - extern int (* printLog)(char const*, ...); -} - -#endif /* defined(__hifi__voxels_Log__) */ -