mirror of
https://github.com/overte-org/overte.git
synced 2025-04-21 18:44:00 +02:00
revises log display
This commit is contained in:
parent
2120ab9b1e
commit
cfd4100c6e
3 changed files with 310 additions and 296 deletions
|
@ -1690,7 +1690,7 @@ void Application::displayOverlay() {
|
|||
glPointSize(1.0f);
|
||||
|
||||
if (_renderStatsOn->isChecked()) { displayStats(); }
|
||||
if (_logOn->isChecked()) { logger.render(_glWidget->width(), _glWidget->height()); }
|
||||
if (_logOn->isChecked()) { logdisplay::Render(_glWidget->width(), _glWidget->height()); }
|
||||
|
||||
// Show chat entry field
|
||||
if (_chatEntryOn) {
|
||||
|
|
|
@ -8,313 +8,356 @@
|
|||
|
||||
#include "Log.h"
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#include "InterfaceConfig.h"
|
||||
|
||||
#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
|
||||
namespace logdisplay {
|
||||
|
||||
const char* FONT_FAMILY = SANS_FONT_FAMILY;
|
||||
|
||||
bool const TEXT_MONOSPACED = true;
|
||||
class Logger {
|
||||
public:
|
||||
Logger();
|
||||
~Logger();
|
||||
|
||||
float const TEXT_RED = 0.7f;
|
||||
float const TEXT_GREEN = 0.6f;
|
||||
float const TEXT_BLUE = 1.0f;
|
||||
inline void render(unsigned screenWidth, unsigned screenHeight);
|
||||
|
||||
// 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;
|
||||
inline void setStream(FILE* stream);
|
||||
inline void setLogWidth(unsigned pixels);
|
||||
inline void setCharacterSize(unsigned width, unsigned height);
|
||||
|
||||
// unsigned integer division rounded towards infinity
|
||||
unsigned divRoundUp(unsigned l, unsigned r) { return (l + r - 1) / r; }
|
||||
}
|
||||
// format, eventually forward, and add the log message (called by printLog)
|
||||
inline int vprint(char const* fmt, va_list);
|
||||
|
||||
Log::Log(FILE* tPipeTo, unsigned bufferedLines,
|
||||
unsigned defaultLogWidth, unsigned defaultCharWidth, unsigned defaultCharHeight) :
|
||||
private:
|
||||
// don't copy/assign
|
||||
Logger(Logger const&); // = delete;
|
||||
Logger& operator=(Logger const&); // = delete;
|
||||
|
||||
_stream(tPipeTo),
|
||||
_chars(0l),
|
||||
_lines(0l),
|
||||
_logWidth(defaultLogWidth) {
|
||||
// add formatted message for console diplay (called by vprint)
|
||||
inline void addMessage(char const*);
|
||||
|
||||
pthread_mutex_init(& _mutex, 0l);
|
||||
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
|
||||
|
||||
// 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;
|
||||
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
|
||||
|
||||
// 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*));
|
||||
unsigned _logWidth; // width of the log in pixels
|
||||
unsigned _charWidth; // width of a character in pixels
|
||||
unsigned _charHeight; // height of a character in pixels
|
||||
|
||||
setCharacterSize(defaultCharWidth, defaultCharHeight);
|
||||
}
|
||||
pthread_mutex_t _mutex;
|
||||
};
|
||||
|
||||
|
||||
Log::~Log() {
|
||||
//
|
||||
// Initialization / state management
|
||||
//
|
||||
|
||||
delete[] _chars;
|
||||
delete[] _lines;
|
||||
}
|
||||
Logger::Logger() :
|
||||
|
||||
inline void Log::addMessage(char const* ptr) {
|
||||
_textRenderer(MONO_FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT),
|
||||
_stream(DEFAULT_STREAM),
|
||||
_chars(0l),
|
||||
_lines(0l),
|
||||
_logWidth(DEFAULT_CONSOLE_WIDTH) {
|
||||
|
||||
// precondition: mutex is locked so noone gets in our way
|
||||
pthread_mutex_init(& _mutex, 0l);
|
||||
|
||||
// T-pipe, if requested
|
||||
if (_stream != 0l) {
|
||||
fprintf(_stream, "%s", ptr);
|
||||
// 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);
|
||||
}
|
||||
|
||||
while (*ptr != '\0') {
|
||||
// process the characters
|
||||
char c = *ptr++;
|
||||
|
||||
if (c == '\t') {
|
||||
Logger::~Logger() {
|
||||
|
||||
// found TAB -> write SPACE
|
||||
c = ' ';
|
||||
delete[] _chars;
|
||||
delete[] _lines;
|
||||
}
|
||||
|
||||
} else if (c == '\n') {
|
||||
inline void Logger::setStream(FILE* stream) {
|
||||
|
||||
// found LF -> write NUL (c == '\0' tells us to wrap, below)
|
||||
c = '\0';
|
||||
}
|
||||
*_writePos++ = c;
|
||||
pthread_mutex_lock(& _mutex);
|
||||
_stream = stream;
|
||||
pthread_mutex_unlock(& _mutex);
|
||||
}
|
||||
|
||||
if (_writePos == _charsEnd) {
|
||||
// reached the end of the circular character buffer? -> start over
|
||||
_writePos = _chars;
|
||||
inline void Logger::setLogWidth(unsigned pixels) {
|
||||
|
||||
pthread_mutex_lock(& _mutex);
|
||||
_logWidth = pixels;
|
||||
_lineLength = _logWidth / _charWidth;
|
||||
pthread_mutex_unlock(& _mutex);
|
||||
}
|
||||
|
||||
inline void Logger::setCharacterSize(unsigned width, unsigned height) {
|
||||
|
||||
pthread_mutex_lock(& _mutex);
|
||||
_charWidth = width;
|
||||
_charHeight = height;
|
||||
_lineLength = _logWidth / _charWidth;
|
||||
pthread_mutex_unlock(& _mutex);
|
||||
}
|
||||
|
||||
//
|
||||
// Logging
|
||||
//
|
||||
|
||||
inline int Logger::vprint(char const* fmt, va_list args) {
|
||||
pthread_mutex_lock(& _mutex);
|
||||
|
||||
// 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(_stream != 0l ? _stream : stderr,
|
||||
"Log: Failed to log message with format string = \"%s\".\n", fmt);
|
||||
}
|
||||
|
||||
if (++_writtenInLine >= _lineLength || c == '\0') {
|
||||
pthread_mutex_unlock(& _mutex);
|
||||
return n;
|
||||
}
|
||||
|
||||
// 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;
|
||||
inline void Logger::addMessage(char const* ptr) {
|
||||
|
||||
// debug mode: make sure all line pointers we write here are valid
|
||||
assert(! (_lastLinePos < _lines || _lastLinePos >= _linesEnd));
|
||||
assert(! (*_lastLinePos < _chars || *_lastLinePos >= _charsEnd));
|
||||
// precondition: mutex is locked so noone gets in our way
|
||||
|
||||
// terminate line, unless done already
|
||||
if (c != '\0') {
|
||||
*_writePos++ = '\0';
|
||||
// T-pipe, if requested
|
||||
if (_stream != 0l) {
|
||||
fprintf(_stream, "%s", ptr);
|
||||
}
|
||||
|
||||
if (_writePos == _charsEnd) {
|
||||
_writePos = _chars;
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
// remember start position in character buffer for next line and reset character count
|
||||
_writeLineStartPos = _writePos;
|
||||
_writtenInLine = 0;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
//
|
||||
// Rendering
|
||||
//
|
||||
|
||||
int Log::vprint(char const* fmt, va_list args) {
|
||||
pthread_mutex_lock(& _mutex);
|
||||
inline void Logger::render(unsigned screenWidth, unsigned screenHeight) {
|
||||
|
||||
// print to buffer
|
||||
char buf[MAX_MESSAGE_LENGTH];
|
||||
int n = vsnprintf(buf, MAX_MESSAGE_LENGTH, fmt, args);
|
||||
if (n > 0) {
|
||||
// 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);
|
||||
|
||||
// all fine? log the message
|
||||
addMessage(buf);
|
||||
// determine number of visible lines (integer division rounded up)
|
||||
unsigned showLines = (screenHeight + _charHeight - 1) / _charHeight;
|
||||
|
||||
} else {
|
||||
char** lastLine = _lastLinePos;
|
||||
char** firstLine = _lastLinePos;
|
||||
|
||||
// error? -> mutter on stream or stderr
|
||||
fprintf(_stream != 0l ? _stream : stderr,
|
||||
"Log: Failed to log message with format string = \"%s\".\n", fmt);
|
||||
}
|
||||
if (! *lastLine) {
|
||||
// empty log
|
||||
pthread_mutex_unlock(& _mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(& _mutex);
|
||||
return n;
|
||||
}
|
||||
// scan for first line
|
||||
for (int n = 2; n <= showLines; ++n) {
|
||||
|
||||
void Log::operator()(char const* fmt, ...) {
|
||||
char** prevFirstLine = firstLine;
|
||||
--firstLine;
|
||||
if (firstLine < _lines) {
|
||||
firstLine = _linesEnd - 1;
|
||||
}
|
||||
if (! *firstLine) {
|
||||
firstLine = prevFirstLine;
|
||||
showLines = n - 1;
|
||||
break;
|
||||
}
|
||||
|
||||
va_list args;
|
||||
va_start(args,fmt);
|
||||
vprint(fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
// debug mode: make sure all line pointers we find here are valid
|
||||
assert(! (firstLine < _lines || firstLine >= _linesEnd));
|
||||
assert(! (*firstLine < _chars || *firstLine >= _charsEnd));
|
||||
}
|
||||
|
||||
void Log::setLogWidth(unsigned pixels) {
|
||||
// copy the line buffer portion into a contiguous region at _linesEnd
|
||||
if (firstLine <= lastLine) {
|
||||
|
||||
pthread_mutex_lock(& _mutex);
|
||||
_logWidth = pixels;
|
||||
_lineLength = _logWidth / _charWidth;
|
||||
pthread_mutex_unlock(& _mutex);
|
||||
}
|
||||
memcpy(_linesEnd, firstLine, showLines * sizeof(char*));
|
||||
|
||||
void Log::setCharacterSize(unsigned width, unsigned height) {
|
||||
} else {
|
||||
|
||||
pthread_mutex_lock(& _mutex);
|
||||
_charWidth = width;
|
||||
_charHeight = height;
|
||||
_charYoffset = height * CHAR_FRACT_BASELINE;
|
||||
_charScale = float(width) / CHAR_WIDTH;
|
||||
_charAspect = (height * CHAR_WIDTH) / (width * CHAR_HEIGHT);
|
||||
_lineLength = _logWidth / _charWidth;
|
||||
pthread_mutex_unlock(& _mutex);
|
||||
}
|
||||
unsigned atEnd = _linesEnd - firstLine;
|
||||
memcpy(_linesEnd, firstLine, atEnd * sizeof(char*));
|
||||
memcpy(_linesEnd + atEnd, _lines, (showLines - atEnd) * sizeof(char*));
|
||||
}
|
||||
|
||||
static TextRenderer* textRenderer() {
|
||||
static TextRenderer* renderer = new TextRenderer(FONT_FAMILY, -1, -1, false, TextRenderer::SHADOW_EFFECT);
|
||||
return renderer;
|
||||
}
|
||||
// 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) {
|
||||
|
||||
void Log::render(unsigned screenWidth, unsigned screenHeight) {
|
||||
memcpy(_charsEnd, firstChar, lastChar - firstChar + 1);
|
||||
|
||||
// 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);
|
||||
} else {
|
||||
|
||||
// determine number of visible lines
|
||||
unsigned showLines = divRoundUp(screenHeight, _charHeight);
|
||||
unsigned atEnd = _charsEnd - firstChar;
|
||||
memcpy(_charsEnd, firstChar, atEnd);
|
||||
memcpy(_charsEnd + atEnd, _chars, lastChar + 1 - _chars);
|
||||
|
||||
char** lastLine = _lastLinePos;
|
||||
char** firstLine = _lastLinePos;
|
||||
charOffsetBeforeFirst = _charsEnd + atEnd - _chars;
|
||||
}
|
||||
|
||||
if (! *lastLine) {
|
||||
// empty log
|
||||
// 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);
|
||||
return;
|
||||
}
|
||||
|
||||
// scan for first line
|
||||
for (int n = 2; n <= showLines; ++n) {
|
||||
glPushMatrix();
|
||||
glScalef(xScale, yScale, 1.0f);
|
||||
for (int y = yStart; y > 0; y -= yStep) {
|
||||
|
||||
char** prevFirstLine = firstLine;
|
||||
--firstLine;
|
||||
if (firstLine < _lines) {
|
||||
firstLine = _linesEnd - 1;
|
||||
// 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
|
||||
glColor3f(TEXT_COLOR_RED, TEXT_COLOR_GREEN, TEXT_COLOR_BLUE);
|
||||
_textRenderer.draw(xStart, y, chars);
|
||||
|
||||
//fprintf(stderr, "Logger::render, message = \"%s\"\n", chars);
|
||||
}
|
||||
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));
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
// copy the line buffer portion into a contiguous region at _linesEnd
|
||||
if (firstLine <= lastLine) {
|
||||
|
||||
memcpy(_linesEnd, firstLine, showLines * sizeof(char*));
|
||||
//
|
||||
// There's one Logger and it exists globally...
|
||||
//
|
||||
Logger logger;
|
||||
|
||||
} else {
|
||||
// Entrypoints
|
||||
void Render(unsigned screenWidth, unsigned screenHeight) { logger.render(screenWidth, screenHeight); }
|
||||
void SetStream(FILE* stream) { logger.setStream(stream); }
|
||||
void SetLogWidth(unsigned pixels) { logger.setLogWidth(pixels); }
|
||||
void SetCharacterSize(unsigned width, unsigned height) { logger.setCharacterSize(width, height); }
|
||||
|
||||
unsigned atEnd = _linesEnd - firstLine;
|
||||
memcpy(_linesEnd, firstLine, atEnd * sizeof(char*));
|
||||
memcpy(_linesEnd + atEnd, _lines, (showLines - atEnd) * sizeof(char*));
|
||||
}
|
||||
} // namespace logdisplay
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
// get values for rendering
|
||||
int yStep = textRenderer()->metrics().lineSpacing();
|
||||
int yStart = screenHeight - textRenderer()->metrics().descent();
|
||||
|
||||
// render text
|
||||
char** line = _linesEnd + showLines;
|
||||
int x = screenWidth - _logWidth;
|
||||
|
||||
pthread_mutex_unlock(& _mutex);
|
||||
// ok, we got all we need
|
||||
|
||||
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
|
||||
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);
|
||||
result = logdisplay::logger.vprint(fmt, args);
|
||||
va_end(args);
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -11,87 +11,58 @@
|
|||
|
||||
#include <stdio.h>
|
||||
#include <stdarg.h>
|
||||
#include <glm/glm.hpp>
|
||||
#include <pthread.h>
|
||||
|
||||
class Log;
|
||||
|
||||
//
|
||||
// Call it as you would call 'printf'.
|
||||
// Log function. Call it as you would call 'printf'.
|
||||
//
|
||||
int printLog(char const* fmt, ...);
|
||||
|
||||
//
|
||||
// Logging control.
|
||||
//
|
||||
namespace logdisplay {
|
||||
|
||||
void Render(unsigned screenWidth, unsigned screenHeight);
|
||||
|
||||
// settings
|
||||
|
||||
static float const TEXT_COLOR_RED = 0.7f;
|
||||
static float const TEXT_COLOR_GREEN = 0.6f;
|
||||
static float const TEXT_COLOR_BLUE = 1.0f;
|
||||
|
||||
static FILE* DEFAULT_STREAM = stdout;
|
||||
static unsigned const DEFAULT_CHAR_WIDTH = 7;
|
||||
static unsigned const DEFAULT_CHAR_HEIGHT = 16;
|
||||
static unsigned const DEFAULT_CONSOLE_WIDTH = 400;
|
||||
|
||||
void SetStream(FILE* stream);
|
||||
void SetLogWidth(unsigned pixels);
|
||||
void SetCharacterSize(unsigned width, unsigned height);
|
||||
|
||||
// limits
|
||||
|
||||
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
|
||||
}
|
||||
|
||||
//
|
||||
// Macro to log OpenGl errors.
|
||||
// Example: oglLog( glPushMatrix() );
|
||||
// Example: printGlError( glPushMatrix() );
|
||||
//
|
||||
#define oGlLog(stmt) \
|
||||
#define printLogGlError(stmt) \
|
||||
stmt; \
|
||||
{ \
|
||||
GLenum e = glGetError(); \
|
||||
if (e != GL_NO_ERROR) { \
|
||||
printLog(__FILE__ ":" oGlLog_stringize(__LINE__) \
|
||||
printLog(__FILE__ ":" printLogGlError_stringize(__LINE__) \
|
||||
" [OpenGL] %s\n", gluErrorString(e)); \
|
||||
} \
|
||||
} \
|
||||
(void) 0
|
||||
|
||||
#define oGlLog_stringize(x) oGlLog_stringize_i(x)
|
||||
#define oGlLog_stringize_i(x) # x
|
||||
|
||||
//
|
||||
// Global instance.
|
||||
//
|
||||
extern Log logger;
|
||||
|
||||
//
|
||||
// Logging subsystem.
|
||||
//
|
||||
class Log {
|
||||
FILE* _stream;
|
||||
char* _chars;
|
||||
char* _charsEnd;
|
||||
char** _lines;
|
||||
char** _linesEnd;
|
||||
|
||||
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
|
||||
unsigned _charYoffset; // baseline offset in pixels
|
||||
float _charScale; // scale factor
|
||||
float _charAspect; // aspect (h/w)
|
||||
|
||||
pthread_mutex_t _mutex;
|
||||
|
||||
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
|
||||
};
|
||||
#define printLogGlError_stringize(x) printLogGlError_stringize_i(x)
|
||||
#define printLogGlError_stringize_i(x) # x
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in a new issue