mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-06-18 19:00:39 +02:00
Merge pull request #352 from tschw/master
refactors logging, adds comments, and revises names & formatting in all submitted code
This commit is contained in:
commit
8b65fcae75
41 changed files with 1100 additions and 1385 deletions
|
@ -37,13 +37,10 @@
|
||||||
#include <AgentTypes.h>
|
#include <AgentTypes.h>
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
#include <PerfStat.h>
|
#include <PerfStat.h>
|
||||||
#include <shared_Log.h>
|
|
||||||
#include <voxels_Log.h>
|
|
||||||
#include <avatars_Log.h>
|
|
||||||
|
|
||||||
#include "Application.h"
|
#include "Application.h"
|
||||||
#include "InterfaceConfig.h"
|
#include "InterfaceConfig.h"
|
||||||
#include "Log.h"
|
#include "LogDisplay.h"
|
||||||
#include "OculusManager.h"
|
#include "OculusManager.h"
|
||||||
#include "Util.h"
|
#include "Util.h"
|
||||||
#include "renderer/ProgramObject.h"
|
#include "renderer/ProgramObject.h"
|
||||||
|
@ -161,10 +158,6 @@ Application::Application(int& argc, char** argv) :
|
||||||
|
|
||||||
_voxels.setViewFrustum(&_viewFrustum);
|
_voxels.setViewFrustum(&_viewFrustum);
|
||||||
|
|
||||||
shared_lib::printLog = & ::printLog;
|
|
||||||
voxels_lib::printLog = & ::printLog;
|
|
||||||
avatars_lib::printLog = & ::printLog;
|
|
||||||
|
|
||||||
unsigned int listenPort = AGENT_SOCKET_LISTEN_PORT;
|
unsigned int listenPort = AGENT_SOCKET_LISTEN_PORT;
|
||||||
const char** constArgv = const_cast<const char**>(argv);
|
const char** constArgv = const_cast<const char**>(argv);
|
||||||
const char* portStr = getCmdOption(argc, constArgv, "--listenPort");
|
const char* portStr = getCmdOption(argc, constArgv, "--listenPort");
|
||||||
|
@ -1774,7 +1767,7 @@ void Application::displayOverlay() {
|
||||||
glPointSize(1.0f);
|
glPointSize(1.0f);
|
||||||
|
|
||||||
if (_renderStatsOn->isChecked()) { displayStats(); }
|
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
|
// Show chat entry field
|
||||||
if (_chatEntryOn) {
|
if (_chatEntryOn) {
|
||||||
|
|
|
@ -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 <string.h>
|
|
||||||
#include <stdarg.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
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
|
@ -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 <stdio.h>
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
#include <pthread.h>
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
306
interface/src/LogDisplay.cpp
Normal file
306
interface/src/LogDisplay.cpp
Normal file
|
@ -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 <stdio.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#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();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
80
interface/src/LogDisplay.h
Normal file
80
interface/src/LogDisplay.h
Normal file
|
@ -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 <stdarg.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
|
@ -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 <sstream>
|
|
||||||
|
|
||||||
#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
|
|
|
@ -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
|
|
|
@ -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),
|
enabled(isEnabled),
|
||||||
inputPaused(false),
|
inputPaused(false),
|
||||||
_valWidth(w),
|
_width(w),
|
||||||
_valHeight(h),
|
_height(h),
|
||||||
_arrSamples(0l),
|
_samples(0l),
|
||||||
_arrVertices(0l),
|
_vertices(0l),
|
||||||
_valLowpass(0.4f),
|
// some filtering (see details in Log.h)
|
||||||
_valDownsample(3) {
|
_lowPassCoeff(0.4f),
|
||||||
|
// three in -> one out
|
||||||
|
_downsampleRatio(3) {
|
||||||
|
|
||||||
// allocate enough space for the sample data and to turn it into
|
// allocate enough space for the sample data and to turn it into
|
||||||
// vertices and since they're all 'short', do so in one shot
|
// vertices and since they're all 'short', do so in one shot
|
||||||
_arrSamples = new short[N_INT16_TO_ALLOC];
|
_samples = new short[N_INT16_TO_ALLOC];
|
||||||
memset(_arrSamples, 0, N_INT16_TO_ALLOC * sizeof(short));
|
memset(_samples, 0, N_INT16_TO_ALLOC * sizeof(short));
|
||||||
_arrVertices = _arrSamples + MAX_SAMPLES;
|
_vertices = _samples + MAX_SAMPLES;
|
||||||
|
|
||||||
// initialize write positions to start of each channel's region
|
// initialize write positions to start of each channel's region
|
||||||
for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) {
|
for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) {
|
||||||
_arrWritePos[ch] = MAX_SAMPLES_PER_CHANNEL * ch;
|
_writePos[ch] = MAX_SAMPLES_PER_CHANNEL * ch;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Oscilloscope::~Oscilloscope() {
|
Oscilloscope::~Oscilloscope() {
|
||||||
|
|
||||||
delete[] _arrSamples;
|
delete[] _samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Oscilloscope::addSamples(unsigned ch, short const* data, unsigned n) {
|
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;
|
unsigned endOffs = baseOffs + MAX_SAMPLES_PER_CHANNEL;
|
||||||
|
|
||||||
// fetch write position for this channel
|
// fetch write position for this channel
|
||||||
unsigned writePos = _arrWritePos[ch];
|
unsigned writePos = _writePos[ch];
|
||||||
|
|
||||||
// determine write position after adding the samples
|
// determine write position after adding the samples
|
||||||
unsigned newWritePos = writePos + n;
|
unsigned newWritePos = writePos + n;
|
||||||
|
@ -83,13 +85,13 @@ void Oscilloscope::addSamples(unsigned ch, short const* data, unsigned n) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// copy data
|
// copy data
|
||||||
memcpy(_arrSamples + writePos, data, n * sizeof(short));
|
memcpy(_samples + writePos, data, n * sizeof(short));
|
||||||
if (n2 > 0) {
|
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
|
// set new write position for this channel
|
||||||
_arrWritePos[ch] = newWritePos;
|
_writePos[ch] = newWritePos;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Oscilloscope::render(int x, int y) {
|
void Oscilloscope::render(int x, int y) {
|
||||||
|
@ -98,20 +100,20 @@ void Oscilloscope::render(int x, int y) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine lowpass / downsample factors
|
// fetch low pass factor (and convert to fix point) / downsample factor
|
||||||
int lowpass = -int(std::numeric_limits<short>::min()) * _valLowpass;
|
int lowPassFixPt = -int(std::numeric_limits<short>::min()) * _lowPassCoeff;
|
||||||
unsigned downsample = _valDownsample;
|
unsigned downsample = _downsampleRatio;
|
||||||
// keep half of the buffer for writing and ensure an even vertex count
|
// 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;
|
unsigned usedSamples = usedWidth * downsample;
|
||||||
|
|
||||||
// expand samples to vertex data
|
// expand samples to vertex data
|
||||||
for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) {
|
for (unsigned ch = 0; ch < MAX_CHANNELS; ++ch) {
|
||||||
// for each channel: determine memory regions
|
// 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* endPtr = basePtr + MAX_SAMPLES_PER_CHANNEL;
|
||||||
short const* inPtr = _arrSamples + _arrWritePos[ch];
|
short const* inPtr = _samples + _writePos[ch];
|
||||||
short* outPtr = _arrVertices + MAX_COORDS_PER_CHANNEL * ch;
|
short* outPtr = _vertices + MAX_COORDS_PER_CHANNEL * ch;
|
||||||
int sample = 0, x = usedWidth;
|
int sample = 0, x = usedWidth;
|
||||||
for (int i = int(usedSamples); --i >= 0 ;) {
|
for (int i = int(usedSamples); --i >= 0 ;) {
|
||||||
if (inPtr == basePtr) {
|
if (inPtr == basePtr) {
|
||||||
|
@ -119,7 +121,7 @@ void Oscilloscope::render(int x, int y) {
|
||||||
inPtr = endPtr;
|
inPtr = endPtr;
|
||||||
}
|
}
|
||||||
// read and (eventually) filter sample
|
// 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
|
// write every nth as y with a corresponding x-coordinate
|
||||||
if (i % downsample == 0) {
|
if (i % downsample == 0) {
|
||||||
*outPtr++ = short(--x);
|
*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);
|
glLineWidth(1.0);
|
||||||
glDisable(GL_LINE_SMOOTH);
|
glDisable(GL_LINE_SMOOTH);
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
glTranslatef((float)x + 0.0f, (float)y + _valHeight / 2.0f, 0.0f);
|
glTranslatef((float)x + 0.0f, (float)y + _height / 2.0f, 0.0f);
|
||||||
glScaled(1.0f, _valHeight / 32767.0f, 1.0f);
|
glScaled(1.0f, _height / 32767.0f, 1.0f);
|
||||||
glVertexPointer(2, GL_SHORT, 0, _arrVertices);
|
glVertexPointer(2, GL_SHORT, 0, _vertices);
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
|
|
||||||
// render channel 0
|
// render channel 0
|
||||||
|
|
|
@ -17,17 +17,43 @@ public:
|
||||||
~Oscilloscope();
|
~Oscilloscope();
|
||||||
|
|
||||||
void addSamples(unsigned ch, short const* data, unsigned n);
|
void addSamples(unsigned ch, short const* data, unsigned n);
|
||||||
|
|
||||||
void render(int x, int y);
|
void render(int x, int y);
|
||||||
|
|
||||||
static unsigned const MAX_CHANNELS = 3;
|
// Switches: On/Off, Stop Time
|
||||||
static unsigned const MAX_SAMPLES_PER_CHANNEL = 4096;
|
|
||||||
|
|
||||||
volatile bool enabled;
|
volatile bool enabled;
|
||||||
volatile bool inputPaused;
|
volatile bool inputPaused;
|
||||||
|
|
||||||
void setLowpass(float w) { assert(w > 0.0f && w <= 1.0f); _valLowpass = w; }
|
// Limits
|
||||||
void setDownsampling(unsigned f) { assert(f > 0); _valDownsample = f; }
|
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:
|
private:
|
||||||
// don't copy/assign
|
// don't copy/assign
|
||||||
|
@ -36,14 +62,14 @@ private:
|
||||||
|
|
||||||
// state variables
|
// state variables
|
||||||
|
|
||||||
unsigned _valWidth;
|
unsigned _width;
|
||||||
unsigned _valHeight;
|
unsigned _height;
|
||||||
short* _arrSamples;
|
short* _samples;
|
||||||
short* _arrVertices;
|
short* _vertices;
|
||||||
unsigned _arrWritePos[MAX_CHANNELS];
|
unsigned _writePos[MAX_CHANNELS];
|
||||||
|
|
||||||
float _valLowpass;
|
float _lowPassCoeff;
|
||||||
unsigned _valDownsample;
|
unsigned _downsampleRatio;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* defined(__interface__oscilloscope__) */
|
#endif /* defined(__interface__oscilloscope__) */
|
||||||
|
|
|
@ -14,24 +14,24 @@
|
||||||
#undef __interface__Starfield_impl__
|
#undef __interface__Starfield_impl__
|
||||||
|
|
||||||
Stars::Stars() :
|
Stars::Stars() :
|
||||||
_ptrController(0l) {
|
_controller(0l) {
|
||||||
_ptrController = new starfield::Controller;
|
_controller = new starfield::Controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stars::~Stars() {
|
Stars::~Stars() {
|
||||||
delete _ptrController;
|
delete _controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Stars::readInput(const char* url, const char* cacheFile, unsigned limit) {
|
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) {
|
bool Stars::setResolution(unsigned k) {
|
||||||
return _ptrController->setResolution(k);
|
return _controller->setResolution(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Stars::changeLOD(float fraction, float overalloc, float realloc) {
|
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) {
|
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
|
// pull the modelview matrix off the GL stack
|
||||||
glm::mat4 view; glGetFloatv(GL_MODELVIEW_MATRIX, glm::value_ptr(view));
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -17,11 +17,7 @@ namespace starfield { class Controller; }
|
||||||
// Starfield rendering component.
|
// Starfield rendering component.
|
||||||
//
|
//
|
||||||
class Stars {
|
class Stars {
|
||||||
|
|
||||||
starfield::Controller* _ptrController;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Stars();
|
Stars();
|
||||||
~Stars();
|
~Stars();
|
||||||
|
|
||||||
|
@ -73,6 +69,10 @@ class Stars {
|
||||||
// don't copy/assign
|
// don't copy/assign
|
||||||
Stars(Stars const&); // = delete;
|
Stars(Stars const&); // = delete;
|
||||||
Stars& operator=(Stars const&); // delete;
|
Stars& operator=(Stars const&); // delete;
|
||||||
|
|
||||||
|
// variables
|
||||||
|
|
||||||
|
starfield::Controller* _controller;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "InterfaceConfig.h"
|
#include "InterfaceConfig.h"
|
||||||
#include "OGlProgram.h"
|
#include "renderer/ProgramObject.h"
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
|
@ -55,60 +55,26 @@
|
||||||
namespace starfield {
|
namespace starfield {
|
||||||
|
|
||||||
class Controller {
|
class Controller {
|
||||||
|
|
||||||
InputVertices _seqInput;
|
|
||||||
#if STARFIELD_MULTITHREADING
|
|
||||||
mutex _mtxInput;
|
|
||||||
atomic<unsigned> _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<BrightnessLevel> _valLodBrightness;
|
|
||||||
BrightnessLevel _valLodAllocBrightness;
|
|
||||||
|
|
||||||
atomic<Renderer*> _ptrRenderer;
|
|
||||||
|
|
||||||
typedef lock_guard<mutex> 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:
|
public:
|
||||||
|
|
||||||
Controller() :
|
Controller() :
|
||||||
_valTileResolution(20),
|
_tileResolution(20),
|
||||||
_valLodFraction(1.0),
|
_lodFraction(1.0),
|
||||||
_valLodLowWaterMark(0.8),
|
_lodLowWaterMark(0.8),
|
||||||
_valLodHighWaterMark(1.0),
|
_lodHighWaterMark(1.0),
|
||||||
_valLodOveralloc(1.2),
|
_lodOveralloc(1.2),
|
||||||
_valLodNalloc(0),
|
_lodNalloc(0),
|
||||||
_valLodNrender(0),
|
_lodNRender(0),
|
||||||
_valLodBrightness(0),
|
_lodBrightness(0),
|
||||||
_valLodAllocBrightness(0),
|
_lodAllocBrightness(0),
|
||||||
_ptrRenderer(0l) {
|
_renderer(0l) {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if !STARFIELD_MULTITHREADING
|
||||||
|
#define lock
|
||||||
|
#define _(x)
|
||||||
|
#endif
|
||||||
|
|
||||||
bool readInput(const char* url, const char* cacheFile, unsigned limit)
|
bool readInput(const char* url, const char* cacheFile, unsigned limit)
|
||||||
{
|
{
|
||||||
InputVertices vertices;
|
InputVertices vertices;
|
||||||
|
@ -121,13 +87,13 @@ namespace starfield {
|
||||||
|
|
||||||
// input is read, now run the entire data pipeline on the new input
|
// 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
|
#if STARFIELD_MULTITHREADING
|
||||||
unsigned k = _valTileResolution.load(memory_order_relaxed);
|
unsigned k = _tileResolution.load(memory_order_relaxed);
|
||||||
#else
|
#else
|
||||||
unsigned k = _valTileResolution;
|
unsigned k = _tileResolution;
|
||||||
#endif
|
#endif
|
||||||
size_t n, nRender;
|
size_t n, nRender;
|
||||||
BrightnessLevel bMin, b;
|
BrightnessLevel bMin, b;
|
||||||
|
@ -136,27 +102,27 @@ namespace starfield {
|
||||||
// we'll have to build a new LOD state for a new total N,
|
// we'll have to build a new LOD state for a new total N,
|
||||||
// ideally keeping allocation size and number of vertices
|
// 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
|
// reciprocal change N_old/N_new tells us how to scale
|
||||||
// the fractions
|
// 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
|
// initialization? use defaults / previously set values
|
||||||
if (rcpChange == 0.0) {
|
if (rcpChange == 0.0) {
|
||||||
|
|
||||||
rcpChange = 1.0;
|
rcpChange = 1.0;
|
||||||
|
|
||||||
nRender = toBufSize(_valLodFraction * newLast);
|
nRender = toBufSize(_lodFraction * newLast);
|
||||||
n = min(newLast, toBufSize(_valLodOveralloc * nRender));
|
n = min(newLast, toBufSize(_lodOveralloc * nRender));
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
// cannot allocate or render more than we have
|
// cannot allocate or render more than we have
|
||||||
n = min(newLast, _valLodNalloc);
|
n = min(newLast, _lodNalloc);
|
||||||
nRender = min(newLast, _valLodNrender);
|
nRender = min(newLast, _lodNRender);
|
||||||
}
|
}
|
||||||
|
|
||||||
// determine new minimum brightness levels
|
// determine new minimum brightness levels
|
||||||
|
@ -178,26 +144,26 @@ namespace starfield {
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
|
|
||||||
// rollback transaction and rethrow
|
// rollback transaction and rethrow
|
||||||
vertices.swap(_seqInput);
|
vertices.swap(_inputSequence);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
// finally publish the new LOD state
|
// finally publish the new LOD state
|
||||||
|
|
||||||
{ lock _(_mtxLodState);
|
{ lock _(_lodStateMutex);
|
||||||
|
|
||||||
_seqLodBrightness.swap(brightness);
|
_lodBrightnessSequence.swap(brightness);
|
||||||
_valLodFraction *= rcpChange;
|
_lodFraction *= rcpChange;
|
||||||
_valLodLowWaterMark *= rcpChange;
|
_lodLowWaterMark *= rcpChange;
|
||||||
_valLodHighWaterMark *= rcpChange;
|
_lodHighWaterMark *= rcpChange;
|
||||||
_valLodOveralloc *= rcpChange;
|
_lodOveralloc *= rcpChange;
|
||||||
_valLodNalloc = n;
|
_lodNalloc = n;
|
||||||
_valLodNrender = nRender;
|
_lodNRender = nRender;
|
||||||
_valLodAllocBrightness = bMin;
|
_lodAllocBrightness = bMin;
|
||||||
#if STARFIELD_MULTITHREADING
|
#if STARFIELD_MULTITHREADING
|
||||||
_valLodBrightness.store(b, memory_order_relaxed);
|
_lodBrightness.store(b, memory_order_relaxed);
|
||||||
#else
|
#else
|
||||||
_valLodBrightness = b;
|
_lodBrightness = b;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -214,24 +180,24 @@ namespace starfield {
|
||||||
// printLog("Stars.cpp: setResolution(%d)\n", k);
|
// printLog("Stars.cpp: setResolution(%d)\n", k);
|
||||||
|
|
||||||
#if STARFIELD_MULTITHREADING
|
#if STARFIELD_MULTITHREADING
|
||||||
if (k != _valTileResolution.load(memory_order_relaxed))
|
if (k != _tileResolution.load(memory_order_relaxed))
|
||||||
#else
|
#else
|
||||||
if (k != _valTileResolution)
|
if (k != _tileResolution)
|
||||||
#endif
|
#endif
|
||||||
{ lock _(_mtxInput);
|
{ lock _(_inputMutex);
|
||||||
|
|
||||||
unsigned n;
|
unsigned n;
|
||||||
BrightnessLevel b, bMin;
|
BrightnessLevel b, bMin;
|
||||||
|
|
||||||
{ lock _(_mtxLodState);
|
{ lock _(_lodStateMutex);
|
||||||
|
|
||||||
n = _valLodNalloc;
|
n = _lodNalloc;
|
||||||
#if STARFIELD_MULTITHREADING
|
#if STARFIELD_MULTITHREADING
|
||||||
b = _valLodBrightness.load(memory_order_relaxed);
|
b = _lodBrightness.load(memory_order_relaxed);
|
||||||
#else
|
#else
|
||||||
b = _valLodBrightness;
|
b = _lodBrightness;
|
||||||
#endif
|
#endif
|
||||||
bMin = _valLodAllocBrightness;
|
bMin = _lodAllocBrightness;
|
||||||
}
|
}
|
||||||
|
|
||||||
this->retile(n, k, b, bMin);
|
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) {
|
double changeLOD(double factor, double overalloc, double realloc) {
|
||||||
|
|
||||||
assert(overalloc >= realloc && realloc >= 0.0);
|
assert(overalloc >= realloc && realloc >= 0.0);
|
||||||
|
@ -273,13 +220,13 @@ namespace starfield {
|
||||||
BrightnessLevel bMin, b;
|
BrightnessLevel bMin, b;
|
||||||
double fraction, lwm, hwm;
|
double fraction, lwm, hwm;
|
||||||
|
|
||||||
{ lock _(_mtxLodState);
|
{ lock _(_lodStateMutex);
|
||||||
|
|
||||||
// acuire a consistent copy of the current LOD state
|
// acuire a consistent copy of the current LOD state
|
||||||
fraction = _valLodFraction;
|
fraction = _lodFraction;
|
||||||
lwm = _valLodLowWaterMark;
|
lwm = _lodLowWaterMark;
|
||||||
hwm = _valLodHighWaterMark;
|
hwm = _lodHighWaterMark;
|
||||||
size_t last = _seqLodBrightness.size() - 1;
|
size_t last = _lodBrightnessSequence.size() - 1;
|
||||||
|
|
||||||
// apply factor
|
// apply factor
|
||||||
fraction = max(0.0, min(1.0, fraction * factor));
|
fraction = max(0.0, min(1.0, fraction * factor));
|
||||||
|
@ -288,23 +235,23 @@ namespace starfield {
|
||||||
// threshold
|
// threshold
|
||||||
double oaFract = std::min(fraction * (1.0 + overalloc), 1.0);
|
double oaFract = std::min(fraction * (1.0 + overalloc), 1.0);
|
||||||
n = toBufSize(oaFract * last);
|
n = toBufSize(oaFract * last);
|
||||||
bMin = _seqLodBrightness[n];
|
bMin = _lodBrightnessSequence[n];
|
||||||
n = std::upper_bound(
|
n = std::upper_bound(
|
||||||
_seqLodBrightness.begin() + n - 1,
|
_lodBrightnessSequence.begin() + n - 1,
|
||||||
_seqLodBrightness.end(),
|
_lodBrightnessSequence.end(),
|
||||||
bMin, GreaterBrightness() ) - _seqLodBrightness.begin();
|
bMin, GreaterBrightness() ) - _lodBrightnessSequence.begin();
|
||||||
|
|
||||||
// also determine number of vertices to render and brightness
|
// also determine number of vertices to render and brightness
|
||||||
nRender = toBufSize(fraction * last);
|
nRender = toBufSize(fraction * last);
|
||||||
// Note: nRender does not have to be accurate
|
// Note: nRender does not have to be accurate
|
||||||
b = _seqLodBrightness[nRender];
|
b = _lodBrightnessSequence[nRender];
|
||||||
// this setting controls the renderer, also keep b as the
|
// this setting controls the renderer, also keep b as the
|
||||||
// brightness becomes volatile as soon as the mutex is
|
// brightness becomes volatile as soon as the mutex is
|
||||||
// released, so keep b
|
// released, so keep b
|
||||||
#if STARFIELD_MULTITHREADING
|
#if STARFIELD_MULTITHREADING
|
||||||
_valLodBrightness.store(b, memory_order_relaxed);
|
_lodBrightness.store(b, memory_order_relaxed);
|
||||||
#else
|
#else
|
||||||
_valLodBrightness = b;
|
_lodBrightness = b;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// printLog("Stars.cpp: "
|
// printLog("Stars.cpp: "
|
||||||
|
@ -313,69 +260,54 @@ namespace starfield {
|
||||||
|
|
||||||
// will not have to reallocate? set new fraction right away
|
// will not have to reallocate? set new fraction right away
|
||||||
// (it is consistent with the rest of the state in this case)
|
// (it is consistent with the rest of the state in this case)
|
||||||
if (fraction >= _valLodLowWaterMark
|
if (fraction >= _lodLowWaterMark
|
||||||
&& fraction <= _valLodHighWaterMark) {
|
&& fraction <= _lodHighWaterMark) {
|
||||||
|
|
||||||
_valLodFraction = fraction;
|
_lodFraction = fraction;
|
||||||
return fraction;
|
return fraction;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// reallocate
|
// reallocate
|
||||||
|
|
||||||
{ lock _(_mtxInput);
|
{ lock _(_inputMutex);
|
||||||
|
|
||||||
recreateRenderer(n, _valTileResolution, b, bMin);
|
recreateRenderer(n, _tileResolution, b, bMin);
|
||||||
|
|
||||||
// printLog("Stars.cpp: LOD reallocation\n");
|
// printLog("Stars.cpp: LOD reallocation\n");
|
||||||
|
|
||||||
// publish new lod state
|
// publish new lod state
|
||||||
|
|
||||||
{ lock _(_mtxLodState);
|
{ lock _(_lodStateMutex);
|
||||||
|
|
||||||
_valLodNalloc = n;
|
_lodNalloc = n;
|
||||||
_valLodNrender = nRender;
|
_lodNRender = nRender;
|
||||||
|
|
||||||
_valLodFraction = fraction;
|
_lodFraction = fraction;
|
||||||
_valLodLowWaterMark = fraction * (1.0 - realloc);
|
_lodLowWaterMark = fraction * (1.0 - realloc);
|
||||||
_valLodHighWaterMark = fraction * (1.0 + realloc);
|
_lodHighWaterMark = fraction * (1.0 + realloc);
|
||||||
_valLodOveralloc = fraction * (1.0 + overalloc);
|
_lodOveralloc = fraction * (1.0 + overalloc);
|
||||||
_valLodAllocBrightness = bMin;
|
_lodAllocBrightness = bMin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return fraction;
|
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) {
|
void render(float perspective, float angle, mat4 const& orientation, float alpha) {
|
||||||
|
|
||||||
#if STARFIELD_MULTITHREADING
|
#if STARFIELD_MULTITHREADING
|
||||||
// check out renderer
|
// check out renderer
|
||||||
Renderer* renderer = _ptrRenderer.exchange(0l);
|
Renderer* renderer = _renderer.exchange(0l);
|
||||||
#else
|
#else
|
||||||
Renderer* renderer = _ptrRenderer;
|
Renderer* renderer = _renderer;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// have it render
|
// have it render
|
||||||
if (renderer != 0l) {
|
if (renderer != 0l) {
|
||||||
#if STARFIELD_MULTITHREADING
|
#if STARFIELD_MULTITHREADING
|
||||||
BrightnessLevel b = _valLodBrightness.load(memory_order_relaxed);
|
BrightnessLevel b = _lodBrightness.load(memory_order_relaxed);
|
||||||
#else
|
#else
|
||||||
BrightnessLevel b = _valLodBrightness;
|
BrightnessLevel b = _lodBrightness;
|
||||||
#endif
|
#endif
|
||||||
renderer->render(perspective, angle, orientation, b, alpha);
|
renderer->render(perspective, angle, orientation, b, alpha);
|
||||||
}
|
}
|
||||||
|
@ -383,7 +315,7 @@ namespace starfield {
|
||||||
#if STARFIELD_MULTITHREADING
|
#if STARFIELD_MULTITHREADING
|
||||||
// check in - or dispose if there is a new one
|
// check in - or dispose if there is a new one
|
||||||
Renderer* newOne = 0l;
|
Renderer* newOne = 0l;
|
||||||
if (! _ptrRenderer.compare_exchange_strong(newOne, renderer)) {
|
if (! _renderer.compare_exchange_strong(newOne, renderer)) {
|
||||||
|
|
||||||
assert(!! newOne);
|
assert(!! newOne);
|
||||||
delete renderer;
|
delete renderer;
|
||||||
|
@ -396,6 +328,37 @@ namespace starfield {
|
||||||
|
|
||||||
private:
|
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<BrightnessLevel> {
|
struct BrightnessSortScanner : Radix2IntegerScanner<BrightnessLevel> {
|
||||||
|
|
||||||
typedef Radix2IntegerScanner<BrightnessLevel> base;
|
typedef Radix2IntegerScanner<BrightnessLevel> base;
|
||||||
|
@ -420,6 +383,39 @@ namespace starfield {
|
||||||
radix2InplaceSort(dst.begin(), dst.end(), BrightnessSortScanner());
|
radix2InplaceSort(dst.begin(), dst.end(), BrightnessSortScanner());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InputVertices _inputSequence;
|
||||||
|
#if STARFIELD_MULTITHREADING
|
||||||
|
mutex _inputMutex;
|
||||||
|
atomic<unsigned> _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<BrightnessLevel> _lodBrightness;
|
||||||
|
BrightnessLevel _lodAllocBrightness;
|
||||||
|
|
||||||
|
atomic<Renderer*> _renderer;
|
||||||
|
|
||||||
|
typedef lock_guard<mutex> lock;
|
||||||
|
#else
|
||||||
|
BrightnessLevel _lodBrightness;
|
||||||
|
BrightnessLevel _lodAllocBrightness;
|
||||||
|
|
||||||
|
Renderer* _renderer;
|
||||||
|
|
||||||
|
#undef lock
|
||||||
|
#undef _
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,42 +23,32 @@
|
||||||
namespace starfield {
|
namespace starfield {
|
||||||
|
|
||||||
class Loader : UrlReader {
|
class Loader : UrlReader {
|
||||||
|
|
||||||
InputVertices* _ptrVertices;
|
|
||||||
unsigned _valLimit;
|
|
||||||
|
|
||||||
unsigned _valLineNo;
|
|
||||||
char const* _strUrl;
|
|
||||||
|
|
||||||
unsigned _valRecordsRead;
|
|
||||||
BrightnessLevel _valMinBrightness;
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
bool loadVertices(
|
bool loadVertices(
|
||||||
InputVertices& destination, char const* url, char const* cacheFile, unsigned limit)
|
InputVertices& destination, char const* url, char const* cacheFile, unsigned limit)
|
||||||
{
|
{
|
||||||
_ptrVertices = & destination;
|
_vertices = & destination;
|
||||||
_valLimit = limit;
|
_limit = limit;
|
||||||
#if STARFIELD_SAVE_MEMORY
|
#if STARFIELD_SAVE_MEMORY
|
||||||
if (_valLimit == 0 || _valLimit > 60000u)
|
if (_limit == 0 || _limit > 60000u)
|
||||||
_valLimit = 60000u;
|
_limit = 60000u;
|
||||||
#endif
|
#endif
|
||||||
_strUrl = url; // in case we fail early
|
_urlStr = url; // in case we fail early
|
||||||
|
|
||||||
if (! UrlReader::readUrl(url, *this, cacheFile))
|
if (! UrlReader::readUrl(url, *this, cacheFile))
|
||||||
{
|
{
|
||||||
printLog("%s:%d: %s\n",
|
printLog("%s:%d: %s\n",
|
||||||
_strUrl, _valLineNo, getError());
|
_urlStr, _lineNo, getError());
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
printLog("Loaded %u stars.\n", _valRecordsRead);
|
printLog("Loaded %u stars.\n", _recordsRead);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
friend class UrlReader;
|
friend class UrlReader;
|
||||||
|
|
||||||
void begin(char const* url,
|
void begin(char const* url,
|
||||||
|
@ -66,13 +56,13 @@ namespace starfield {
|
||||||
int64_t size,
|
int64_t size,
|
||||||
int64_t stardate) {
|
int64_t stardate) {
|
||||||
|
|
||||||
_valLineNo = 0u;
|
_lineNo = 0u;
|
||||||
_strUrl = url; // new value in http redirect
|
_urlStr = url; // new value in http redirect
|
||||||
|
|
||||||
_valRecordsRead = 0u;
|
_recordsRead = 0u;
|
||||||
|
|
||||||
_ptrVertices->clear();
|
_vertices->clear();
|
||||||
_ptrVertices->reserve(_valLimit);
|
_vertices->reserve(_limit);
|
||||||
// printLog("Stars.cpp: loader begin %s\n", url);
|
// printLog("Stars.cpp: loader begin %s\n", url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,7 +78,7 @@ namespace starfield {
|
||||||
for (; next != end && isspace(*next); ++next);
|
for (; next != end && isspace(*next); ++next);
|
||||||
consumed = next - input;
|
consumed = next - input;
|
||||||
line = next;
|
line = next;
|
||||||
++_valLineNo;
|
++_lineNo;
|
||||||
for (; next != end && *next != '\n' && *next != '\r'; ++next);
|
for (; next != end && *next != '\n' && *next != '\r'; ++next);
|
||||||
if (next == end)
|
if (next == end)
|
||||||
return consumed;
|
return consumed;
|
||||||
|
@ -109,12 +99,12 @@ namespace starfield {
|
||||||
storeVertex(azi, alt, c);
|
storeVertex(azi, alt, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
++_valRecordsRead;
|
++_recordsRead;
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
printLog("Stars.cpp:%d: Bad input from %s\n",
|
printLog("Stars.cpp:%d: Bad input from %s\n",
|
||||||
_valLineNo, _strUrl);
|
_lineNo, _urlStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -126,7 +116,7 @@ namespace starfield {
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
bool atLimit() { return _valLimit > 0u && _valRecordsRead >= _valLimit; }
|
bool atLimit() { return _limit > 0u && _recordsRead >= _limit; }
|
||||||
|
|
||||||
bool spaceFor(BrightnessLevel b) {
|
bool spaceFor(BrightnessLevel b) {
|
||||||
|
|
||||||
|
@ -136,44 +126,55 @@ namespace starfield {
|
||||||
|
|
||||||
// just reached the limit? -> establish a minimum heap and
|
// just reached the limit? -> establish a minimum heap and
|
||||||
// remember the brightness at its top
|
// remember the brightness at its top
|
||||||
if (_valRecordsRead == _valLimit) {
|
if (_recordsRead == _limit) {
|
||||||
|
|
||||||
// printLog("Stars.cpp: vertex limit reached -> heap mode\n");
|
// printLog("Stars.cpp: vertex limit reached -> heap mode\n");
|
||||||
|
|
||||||
make_heap(
|
make_heap(
|
||||||
_ptrVertices->begin(), _ptrVertices->end(),
|
_vertices->begin(), _vertices->end(),
|
||||||
GreaterBrightness() );
|
GreaterBrightness() );
|
||||||
|
|
||||||
_valMinBrightness = getBrightness(
|
_minBrightness = getBrightness(
|
||||||
_ptrVertices->begin()->getColor() );
|
_vertices->begin()->getColor() );
|
||||||
}
|
}
|
||||||
|
|
||||||
// not interested? say so
|
// not interested? say so
|
||||||
if (_valMinBrightness >= b)
|
if (_minBrightness >= b)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// otherwise free up space for the new vertex
|
// otherwise free up space for the new vertex
|
||||||
pop_heap(
|
pop_heap(
|
||||||
_ptrVertices->begin(), _ptrVertices->end(),
|
_vertices->begin(), _vertices->end(),
|
||||||
GreaterBrightness() );
|
GreaterBrightness() );
|
||||||
_ptrVertices->pop_back();
|
_vertices->pop_back();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void storeVertex(float azi, float alt, unsigned color) {
|
void storeVertex(float azi, float alt, unsigned color) {
|
||||||
|
|
||||||
_ptrVertices->push_back(InputVertex(azi, alt, color));
|
_vertices->push_back(InputVertex(azi, alt, color));
|
||||||
|
|
||||||
if (atLimit()) {
|
if (atLimit()) {
|
||||||
|
|
||||||
push_heap(
|
push_heap(
|
||||||
_ptrVertices->begin(), _ptrVertices->end(),
|
_vertices->begin(), _vertices->end(),
|
||||||
GreaterBrightness() );
|
GreaterBrightness() );
|
||||||
|
|
||||||
_valMinBrightness = getBrightness(
|
_minBrightness = getBrightness(
|
||||||
_ptrVertices->begin()->getColor() );
|
_vertices->begin()->getColor() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// variables
|
||||||
|
|
||||||
|
InputVertices* _vertices;
|
||||||
|
unsigned _limit;
|
||||||
|
|
||||||
|
unsigned _lineNo;
|
||||||
|
char const* _urlStr;
|
||||||
|
|
||||||
|
unsigned _recordsRead;
|
||||||
|
BrightnessLevel _minBrightness;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
|
@ -18,18 +18,12 @@
|
||||||
namespace starfield {
|
namespace starfield {
|
||||||
|
|
||||||
class GpuVertex {
|
class GpuVertex {
|
||||||
|
|
||||||
unsigned _valColor;
|
|
||||||
float _valX;
|
|
||||||
float _valY;
|
|
||||||
float _valZ;
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
GpuVertex() { }
|
GpuVertex() { }
|
||||||
|
|
||||||
GpuVertex(InputVertex const& in) {
|
GpuVertex(InputVertex const& in) {
|
||||||
|
|
||||||
_valColor = in.getColor();
|
_color = in.getColor();
|
||||||
float azi = in.getAzimuth();
|
float azi = in.getAzimuth();
|
||||||
float alt = in.getAltitude();
|
float alt = in.getAltitude();
|
||||||
|
|
||||||
|
@ -44,7 +38,13 @@ namespace starfield {
|
||||||
_valZ = gz * exz;
|
_valZ = gz * exz;
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned getColor() const { return _valColor; }
|
unsigned getColor() const { return _color; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned _color;
|
||||||
|
float _valX;
|
||||||
|
float _valY;
|
||||||
|
float _valZ;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
|
@ -18,15 +18,11 @@
|
||||||
namespace starfield {
|
namespace starfield {
|
||||||
|
|
||||||
class InputVertex {
|
class InputVertex {
|
||||||
|
|
||||||
unsigned _valColor;
|
|
||||||
float _valAzimuth;
|
|
||||||
float _valAltitude;
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InputVertex(float azimuth, float altitude, unsigned color) {
|
InputVertex(float azimuth, float altitude, unsigned color) {
|
||||||
|
|
||||||
_valColor = ((color >> 16) & 0xffu) | (color & 0xff00u) |
|
_color = ((color >> 16) & 0xffu) | (color & 0xff00u) |
|
||||||
((color << 16) & 0xff0000u) | 0xff000000u;
|
((color << 16) & 0xff0000u) | 0xff000000u;
|
||||||
|
|
||||||
azimuth = angleConvert<Degrees,Radians>(azimuth);
|
azimuth = angleConvert<Degrees,Radians>(azimuth);
|
||||||
|
@ -34,13 +30,18 @@ namespace starfield {
|
||||||
|
|
||||||
angleHorizontalPolar<Radians>(azimuth, altitude);
|
angleHorizontalPolar<Radians>(azimuth, altitude);
|
||||||
|
|
||||||
_valAzimuth = azimuth;
|
_azimuth = azimuth;
|
||||||
_valAltitude = altitude;
|
_altitude = altitude;
|
||||||
}
|
}
|
||||||
|
|
||||||
float getAzimuth() const { return _valAzimuth; }
|
float getAzimuth() const { return _azimuth; }
|
||||||
float getAltitude() const { return _valAltitude; }
|
float getAltitude() const { return _altitude; }
|
||||||
unsigned getColor() const { return _valColor; }
|
unsigned getColor() const { return _color; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
unsigned _color;
|
||||||
|
float _azimuth;
|
||||||
|
float _altitude;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<InputVertex> InputVertices;
|
typedef std::vector<InputVertex> InputVertices;
|
||||||
|
|
|
@ -25,6 +25,7 @@ namespace starfield {
|
||||||
BrightnessLevel lod;
|
BrightnessLevel lod;
|
||||||
nuint flags;
|
nuint flags;
|
||||||
|
|
||||||
|
// flags
|
||||||
static uint16_t const checked = 1;
|
static uint16_t const checked = 1;
|
||||||
static uint16_t const visited = 2;
|
static uint16_t const visited = 2;
|
||||||
static uint16_t const render = 4;
|
static uint16_t const render = 4;
|
||||||
|
|
|
@ -13,8 +13,6 @@
|
||||||
#error "This is an implementation file - not intended for direct inclusion."
|
#error "This is an implementation file - not intended for direct inclusion."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "renderer/ProgramObject.h"
|
|
||||||
|
|
||||||
#include "starfield/Config.h"
|
#include "starfield/Config.h"
|
||||||
#include "starfield/data/InputVertex.h"
|
#include "starfield/data/InputVertex.h"
|
||||||
#include "starfield/data/BrightnessLevel.h"
|
#include "starfield/data/BrightnessLevel.h"
|
||||||
|
@ -66,22 +64,6 @@
|
||||||
namespace starfield {
|
namespace starfield {
|
||||||
|
|
||||||
class Renderer {
|
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:
|
public:
|
||||||
|
|
||||||
Renderer(InputVertices const& src,
|
Renderer(InputVertices const& src,
|
||||||
|
@ -90,9 +72,9 @@ namespace starfield {
|
||||||
BrightnessLevel b,
|
BrightnessLevel b,
|
||||||
BrightnessLevel bMin) :
|
BrightnessLevel bMin) :
|
||||||
|
|
||||||
_arrData(0l),
|
_dataArray(0l),
|
||||||
_arrTile(0l),
|
_tileArray(0l),
|
||||||
_objTiling(k) {
|
_tiling(k) {
|
||||||
|
|
||||||
this->glAlloc();
|
this->glAlloc();
|
||||||
|
|
||||||
|
@ -103,10 +85,10 @@ namespace starfield {
|
||||||
// REVISIT: batch arrays are probably oversized, but - hey - they
|
// REVISIT: batch arrays are probably oversized, but - hey - they
|
||||||
// are not very large (unless for insane tiling) and we're better
|
// are not very large (unless for insane tiling) and we're better
|
||||||
// off safe than sorry
|
// off safe than sorry
|
||||||
_arrData = new GpuVertex[n];
|
_dataArray = new GpuVertex[n];
|
||||||
_arrTile = new Tile[nTiles + 1];
|
_tileArray = new Tile[nTiles + 1];
|
||||||
_arrBatchOffs = new GLint[nTiles * 2];
|
_batchOffs = new GLint[nTiles * 2];
|
||||||
_arrBatchCount = new GLsizei[nTiles * 2];
|
_batchCountArray = new GLsizei[nTiles * 2];
|
||||||
|
|
||||||
prepareVertexData(src, n, tiling, b, bMin);
|
prepareVertexData(src, n, tiling, b, bMin);
|
||||||
|
|
||||||
|
@ -115,10 +97,10 @@ namespace starfield {
|
||||||
|
|
||||||
~Renderer() {
|
~Renderer() {
|
||||||
|
|
||||||
delete[] _arrData;
|
delete[] _dataArray;
|
||||||
delete[] _arrTile;
|
delete[] _tileArray;
|
||||||
delete[] _arrBatchCount;
|
delete[] _batchCountArray;
|
||||||
delete[] _arrBatchOffs;
|
delete[] _batchOffs;
|
||||||
|
|
||||||
this->glFree();
|
this->glFree();
|
||||||
}
|
}
|
||||||
|
@ -174,30 +156,31 @@ namespace starfield {
|
||||||
|
|
||||||
matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f) * glm::affineInverse(matrix);
|
matrix = glm::frustum(-hw,hw, -hh,hh, nearClip,10.0f) * glm::affineInverse(matrix);
|
||||||
|
|
||||||
this->_itrOutIndex = (unsigned*) _arrBatchOffs;
|
this->_outIndexPos = (unsigned*) _batchOffs;
|
||||||
this->_vecWxform = vec3(row(matrix, 3));
|
this->_wRowVec = vec3(row(matrix, 3));
|
||||||
this->_valHalfPersp = halfPersp;
|
this->_halfPerspectiveAngle = halfPersp;
|
||||||
this->_valMinBright = minBright;
|
this->_minBright = minBright;
|
||||||
|
|
||||||
TileSelection::Cursor cursor;
|
TileSelection::Cursor cursor;
|
||||||
cursor.current = _arrTile + _objTiling.getTileIndex(azimuth, altitude);
|
cursor.current = _tileArray + _tiling.getTileIndex(azimuth, altitude);
|
||||||
cursor.firstInRow = _arrTile + _objTiling.getTileIndex(0.0f, altitude);
|
cursor.firstInRow = _tileArray + _tiling.getTileIndex(0.0f, altitude);
|
||||||
|
|
||||||
floodFill(cursor, TileSelection(*this, _arrTile, _arrTile + _objTiling.getTileCount(),
|
floodFill(cursor, TileSelection(*this, _tileArray, _tileArray + _tiling.getTileCount(),
|
||||||
(TileSelection::Cursor*) _arrBatchCount));
|
(TileSelection::Cursor*) _batchCountArray));
|
||||||
|
|
||||||
#if STARFIELD_DEBUG_CULLING
|
#if STARFIELD_DEBUG_CULLING
|
||||||
# define matrix matrix_debug
|
# define matrix matrix_debug
|
||||||
#endif
|
#endif
|
||||||
this->glBatch(glm::value_ptr(matrix), prepareBatch(
|
this->glBatch(glm::value_ptr(matrix), prepareBatch(
|
||||||
(unsigned*) _arrBatchOffs, _itrOutIndex), alpha);
|
(unsigned*) _batchOffs, _outIndexPos), alpha);
|
||||||
|
|
||||||
#if STARFIELD_DEBUG_CULLING
|
#if STARFIELD_DEBUG_CULLING
|
||||||
# undef matrix
|
# undef matrix
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private: // renderer construction
|
private:
|
||||||
|
// renderer construction
|
||||||
|
|
||||||
void prepareVertexData(InputVertices const& src,
|
void prepareVertexData(InputVertices const& src,
|
||||||
size_t n, // <-- at bMin and brighter
|
size_t n, // <-- at bMin and brighter
|
||||||
|
@ -208,9 +191,9 @@ namespace starfield {
|
||||||
size_t nTiles = tiling.getTileCount();
|
size_t nTiles = tiling.getTileCount();
|
||||||
size_t vertexIndex = 0u, currTileIndex = 0u, count_active = 0u;
|
size_t vertexIndex = 0u, currTileIndex = 0u, count_active = 0u;
|
||||||
|
|
||||||
_arrTile[0].offset = 0u;
|
_tileArray[0].offset = 0u;
|
||||||
_arrTile[0].lod = b;
|
_tileArray[0].lod = b;
|
||||||
_arrTile[0].flags = 0u;
|
_tileArray[0].flags = 0u;
|
||||||
|
|
||||||
for (InputVertices::const_iterator i =
|
for (InputVertices::const_iterator i =
|
||||||
src.begin(), e = src.end(); i != e; ++i) {
|
src.begin(), e = src.end(); i != e; ++i) {
|
||||||
|
@ -227,8 +210,8 @@ namespace starfield {
|
||||||
// moved on to another tile? -> flush
|
// moved on to another tile? -> flush
|
||||||
if (tileIndex != currTileIndex) {
|
if (tileIndex != currTileIndex) {
|
||||||
|
|
||||||
Tile* t = _arrTile + currTileIndex;
|
Tile* t = _tileArray + currTileIndex;
|
||||||
Tile* tLast = _arrTile + tileIndex;
|
Tile* tLast = _tileArray + tileIndex;
|
||||||
|
|
||||||
// set count of active vertices (upcoming lod)
|
// set count of active vertices (upcoming lod)
|
||||||
t->count = count_active;
|
t->count = count_active;
|
||||||
|
@ -253,21 +236,20 @@ namespace starfield {
|
||||||
// printLog("Stars.cpp: Vertex %d on tile #%d\n", vertexIndex, tileIndex);
|
// printLog("Stars.cpp: Vertex %d on tile #%d\n", vertexIndex, tileIndex);
|
||||||
|
|
||||||
// write converted vertex
|
// write converted vertex
|
||||||
_arrData[vertexIndex++] = *i;
|
_dataArray[vertexIndex++] = *i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(vertexIndex == n);
|
assert(vertexIndex == n);
|
||||||
// flush last tile (see above)
|
// flush last tile (see above)
|
||||||
Tile* t = _arrTile + currTileIndex;
|
Tile* t = _tileArray + currTileIndex;
|
||||||
t->count = count_active;
|
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->offset = vertexIndex, t->count = 0u,
|
||||||
t->lod = b, t->flags = 0;
|
t->lod = b, t->flags = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FOV culling / LOD
|
||||||
private: // FOV culling / LOD
|
|
||||||
|
|
||||||
class TileSelection;
|
class TileSelection;
|
||||||
friend class Renderer::TileSelection;
|
friend class Renderer::TileSelection;
|
||||||
|
@ -277,22 +259,22 @@ namespace starfield {
|
||||||
public:
|
public:
|
||||||
struct Cursor { Tile* current, * firstInRow; };
|
struct Cursor { Tile* current, * firstInRow; };
|
||||||
private:
|
private:
|
||||||
Renderer& _refRenderer;
|
Renderer& _rendererRef;
|
||||||
Cursor* const _arrStack;
|
Cursor* const _stackArray;
|
||||||
Cursor* _itrStack;
|
Cursor* _stackPos;
|
||||||
Tile const* const _arrTile;
|
Tile const* const _tileArray;
|
||||||
Tile const* const _ptrTilesEnd;
|
Tile const* const _tilesEnd;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
TileSelection(Renderer& renderer, Tile const* tiles,
|
TileSelection(Renderer& renderer, Tile const* tiles,
|
||||||
Tile const* tiles_end, Cursor* stack) :
|
Tile const* tiles_end, Cursor* stack) :
|
||||||
|
|
||||||
_refRenderer(renderer),
|
_rendererRef(renderer),
|
||||||
_arrStack(stack),
|
_stackArray(stack),
|
||||||
_itrStack(stack),
|
_stackPos(stack),
|
||||||
_arrTile(tiles),
|
_tileArray(tiles),
|
||||||
_ptrTilesEnd(tiles_end) {
|
_tilesEnd(tiles_end) {
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
@ -302,7 +284,7 @@ namespace starfield {
|
||||||
bool select(Cursor const& c) {
|
bool select(Cursor const& c) {
|
||||||
Tile* t = c.current;
|
Tile* t = c.current;
|
||||||
|
|
||||||
if (t < _arrTile || t >= _ptrTilesEnd ||
|
if (t < _tileArray || t >= _tilesEnd ||
|
||||||
!! (t->flags & Tile::checked)) {
|
!! (t->flags & Tile::checked)) {
|
||||||
|
|
||||||
// out of bounds or been here already
|
// out of bounds or been here already
|
||||||
|
@ -311,7 +293,7 @@ namespace starfield {
|
||||||
|
|
||||||
// will check now and never again
|
// will check now and never again
|
||||||
t->flags |= Tile::checked;
|
t->flags |= Tile::checked;
|
||||||
if (_refRenderer.visitTile(t)) {
|
if (_rendererRef.visitTile(t)) {
|
||||||
|
|
||||||
// good one -> remember (for batching) and propagate
|
// good one -> remember (for batching) and propagate
|
||||||
t->flags |= Tile::render;
|
t->flags |= Tile::render;
|
||||||
|
@ -334,39 +316,39 @@ namespace starfield {
|
||||||
void right(Cursor& c) const {
|
void right(Cursor& c) const {
|
||||||
|
|
||||||
c.current += 1;
|
c.current += 1;
|
||||||
if (c.current == c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles()) {
|
if (c.current == c.firstInRow + _rendererRef._tiling.getAzimuthalTiles()) {
|
||||||
c.current = c.firstInRow;
|
c.current = c.firstInRow;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void left(Cursor& c) const {
|
void left(Cursor& c) const {
|
||||||
|
|
||||||
if (c.current == c.firstInRow) {
|
if (c.current == c.firstInRow) {
|
||||||
c.current = c.firstInRow + _refRenderer._objTiling.getAzimuthalTiles();
|
c.current = c.firstInRow + _rendererRef._tiling.getAzimuthalTiles();
|
||||||
}
|
}
|
||||||
c.current -= 1;
|
c.current -= 1;
|
||||||
}
|
}
|
||||||
void up(Cursor& c) const {
|
void up(Cursor& c) const {
|
||||||
|
|
||||||
unsigned d = _refRenderer._objTiling.getAzimuthalTiles();
|
unsigned d = _rendererRef._tiling.getAzimuthalTiles();
|
||||||
c.current += d;
|
c.current += d;
|
||||||
c.firstInRow += d;
|
c.firstInRow += d;
|
||||||
}
|
}
|
||||||
void down(Cursor& c) const {
|
void down(Cursor& c) const {
|
||||||
|
|
||||||
unsigned d = _refRenderer._objTiling.getAzimuthalTiles();
|
unsigned d = _rendererRef._tiling.getAzimuthalTiles();
|
||||||
c.current -= d;
|
c.current -= d;
|
||||||
c.firstInRow -= d;
|
c.firstInRow -= d;
|
||||||
}
|
}
|
||||||
|
|
||||||
void defer(Cursor const& t) {
|
void defer(Cursor const& t) {
|
||||||
|
|
||||||
*_itrStack++ = t;
|
*_stackPos++ = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool deferred(Cursor& cursor) {
|
bool deferred(Cursor& cursor) {
|
||||||
|
|
||||||
if (_itrStack != _arrStack) {
|
if (_stackPos != _stackArray) {
|
||||||
cursor = *--_itrStack;
|
cursor = *--_stackPos;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
|
@ -375,35 +357,35 @@ namespace starfield {
|
||||||
|
|
||||||
bool visitTile(Tile* t) {
|
bool visitTile(Tile* t) {
|
||||||
|
|
||||||
unsigned index = t - _arrTile;
|
unsigned index = t - _tileArray;
|
||||||
*_itrOutIndex++ = index;
|
*_outIndexPos++ = index;
|
||||||
|
|
||||||
if (! tileVisible(t, index)) {
|
if (! tileVisible(t, index)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (t->lod != _valMinBright) {
|
if (t->lod != _minBright) {
|
||||||
updateVertexCount(t, _valMinBright);
|
updateVertexCount(t, _minBright);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool tileVisible(Tile* t, unsigned i) {
|
bool tileVisible(Tile* t, unsigned i) {
|
||||||
|
|
||||||
float slice = _objTiling.getSliceAngle();
|
float slice = _tiling.getSliceAngle();
|
||||||
float halfSlice = 0.5f * slice;
|
float halfSlice = 0.5f * slice;
|
||||||
unsigned stride = _objTiling.getAzimuthalTiles();
|
unsigned stride = _tiling.getAzimuthalTiles();
|
||||||
float azimuth = (i % stride) * slice;
|
float azimuth = (i % stride) * slice;
|
||||||
float altitude = (i / stride) * slice - Radians::halfPi();
|
float altitude = (i / stride) * slice - Radians::halfPi();
|
||||||
float gx = sin(azimuth);
|
float gx = sin(azimuth);
|
||||||
float gz = -cos(azimuth);
|
float gz = -cos(azimuth);
|
||||||
float exz = cos(altitude);
|
float exz = cos(altitude);
|
||||||
vec3 tileCenter = vec3(gx * exz, sin(altitude), gz * exz);
|
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 daz = halfSlice * cos(std::max(0.0f, abs(altitude) - halfSlice));
|
||||||
float dal = 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);
|
// 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
|
// perform a binary search in the so found partition for the
|
||||||
// new vertex count of this tile
|
// new vertex count of this tile
|
||||||
|
|
||||||
GpuVertex const* start = _arrData + t[0].offset;
|
GpuVertex const* start = _dataArray + t[0].offset;
|
||||||
GpuVertex const* end = _arrData + t[1].offset;
|
GpuVertex const* end = _dataArray + t[1].offset;
|
||||||
|
|
||||||
assert(end >= start);
|
assert(end >= start);
|
||||||
|
|
||||||
|
@ -433,9 +415,9 @@ namespace starfield {
|
||||||
end = std::upper_bound(
|
end = std::upper_bound(
|
||||||
start, end, minBright, GreaterBrightness());
|
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;
|
t->lod = minBright;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -443,13 +425,13 @@ namespace starfield {
|
||||||
unsigned const* indicesEnd) {
|
unsigned const* indicesEnd) {
|
||||||
|
|
||||||
unsigned nRanges = 0u;
|
unsigned nRanges = 0u;
|
||||||
GLint* offs = _arrBatchOffs;
|
GLint* offs = _batchOffs;
|
||||||
GLsizei* count = _arrBatchCount;
|
GLsizei* count = _batchCountArray;
|
||||||
|
|
||||||
for (unsigned* i = (unsigned*) _arrBatchOffs;
|
for (unsigned* i = (unsigned*) _batchOffs;
|
||||||
i != indicesEnd; ++i) {
|
i != indicesEnd; ++i) {
|
||||||
|
|
||||||
Tile* t = _arrTile + *i;
|
Tile* t = _tileArray + *i;
|
||||||
if ((t->flags & Tile::render) > 0u && t->count > 0u) {
|
if ((t->flags & Tile::render) > 0u && t->count > 0u) {
|
||||||
|
|
||||||
*offs++ = t->offset;
|
*offs++ = t->offset;
|
||||||
|
@ -461,7 +443,7 @@ namespace starfield {
|
||||||
return nRanges;
|
return nRanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
private: // gl API handling
|
// GL API handling
|
||||||
|
|
||||||
void glAlloc() {
|
void glAlloc() {
|
||||||
|
|
||||||
|
@ -478,28 +460,28 @@ namespace starfield {
|
||||||
" gl_PointSize = s;\n"
|
" gl_PointSize = s;\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
|
|
||||||
_objProgram.addShaderFromSourceCode(QGLShader::Vertex, VERTEX_SHADER);
|
_program.addShaderFromSourceCode(QGLShader::Vertex, VERTEX_SHADER);
|
||||||
GLchar const* const FRAGMENT_SHADER =
|
GLchar const* const FRAGMENT_SHADER =
|
||||||
"#version 120\n"
|
"#version 120\n"
|
||||||
"void main(void) {\n"
|
"void main(void) {\n"
|
||||||
" gl_FragColor = gl_Color;\n"
|
" gl_FragColor = gl_Color;\n"
|
||||||
"}\n";
|
"}\n";
|
||||||
_objProgram.addShaderFromSourceCode(QGLShader::Fragment, FRAGMENT_SHADER);
|
_program.addShaderFromSourceCode(QGLShader::Fragment, FRAGMENT_SHADER);
|
||||||
_objProgram.link();
|
_program.link();
|
||||||
_alphaLocation = _objProgram.uniformLocation("alpha");
|
_alphaLocationHandle = _program.uniformLocation("alpha");
|
||||||
|
|
||||||
glGenBuffersARB(1, & _hndVertexArray);
|
glGenBuffersARB(1, & _vertexArrayHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void glFree() {
|
void glFree() {
|
||||||
|
|
||||||
glDeleteBuffersARB(1, & _hndVertexArray);
|
glDeleteBuffersARB(1, & _vertexArrayHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
void glUpload(GLsizei n) {
|
void glUpload(GLsizei n) {
|
||||||
glBindBufferARB(GL_ARRAY_BUFFER, _hndVertexArray);
|
glBindBufferARB(GL_ARRAY_BUFFER, _vertexArrayHandle);
|
||||||
glBufferData(GL_ARRAY_BUFFER,
|
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);
|
//glInterleavedArrays(GL_C4UB_V3F, sizeof(GpuVertex), 0l);
|
||||||
|
|
||||||
glBindBufferARB(GL_ARRAY_BUFFER, 0);
|
glBindBufferARB(GL_ARRAY_BUFFER, 0);
|
||||||
|
@ -511,7 +493,7 @@ namespace starfield {
|
||||||
|
|
||||||
// for (int i = 0; i < n_ranges; ++i)
|
// for (int i = 0; i < n_ranges; ++i)
|
||||||
// printLog("Stars.cpp: Batch #%d - %d stars @ %d\n", 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_DEPTH_TEST);
|
||||||
glDisable(GL_LIGHTING);
|
glDisable(GL_LIGHTING);
|
||||||
|
@ -533,24 +515,42 @@ namespace starfield {
|
||||||
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||||
|
|
||||||
// select shader and vertex array
|
// select shader and vertex array
|
||||||
_objProgram.bind();
|
_program.bind();
|
||||||
_objProgram.setUniformValue(_alphaLocation, alpha);
|
_program.setUniformValue(_alphaLocationHandle, alpha);
|
||||||
glBindBufferARB(GL_ARRAY_BUFFER, _hndVertexArray);
|
glBindBufferARB(GL_ARRAY_BUFFER, _vertexArrayHandle);
|
||||||
glInterleavedArrays(GL_C4UB_V3F, sizeof(GpuVertex), 0l);
|
glInterleavedArrays(GL_C4UB_V3F, sizeof(GpuVertex), 0l);
|
||||||
|
|
||||||
// render
|
// render
|
||||||
glMultiDrawArrays(GL_POINTS,
|
glMultiDrawArrays(GL_POINTS,
|
||||||
_arrBatchOffs, _arrBatchCount, n_ranges);
|
_batchOffs, _batchCountArray, n_ranges);
|
||||||
|
|
||||||
// restore state
|
// restore state
|
||||||
glBindBufferARB(GL_ARRAY_BUFFER, 0);
|
glBindBufferARB(GL_ARRAY_BUFFER, 0);
|
||||||
_objProgram.release();
|
_program.release();
|
||||||
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||||
glDisable(GL_POINT_SMOOTH);
|
glDisable(GL_POINT_SMOOTH);
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
glMatrixMode(GL_MODELVIEW);
|
glMatrixMode(GL_MODELVIEW);
|
||||||
glPopMatrix();
|
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
|
} // anonymous namespace
|
||||||
|
|
|
@ -18,22 +18,17 @@
|
||||||
namespace starfield {
|
namespace starfield {
|
||||||
|
|
||||||
class Tiling {
|
class Tiling {
|
||||||
|
|
||||||
unsigned _valK;
|
|
||||||
float _valRcpSlice;
|
|
||||||
unsigned _valBits;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Tiling(unsigned k) :
|
Tiling(unsigned k) :
|
||||||
_valK(k),
|
_valK(k),
|
||||||
_valRcpSlice(k / Radians::twicePi()) {
|
_rcpSlice(k / Radians::twicePi()) {
|
||||||
_valBits = ceil(log(getTileCount()) * 1.4426950408889634); // log2
|
_nBits = ceil(log(getTileCount()) * 1.4426950408889634); // log2
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned getAzimuthalTiles() const { return _valK; }
|
unsigned getAzimuthalTiles() const { return _valK; }
|
||||||
unsigned getAltitudinalTiles() const { return _valK / 2 + 1; }
|
unsigned getAltitudinalTiles() const { return _valK / 2 + 1; }
|
||||||
unsigned getTileIndexBits() const { return _valBits; }
|
unsigned getTileIndexBits() const { return _nBits; }
|
||||||
|
|
||||||
unsigned getTileCount() const {
|
unsigned getTileCount() const {
|
||||||
return getAzimuthalTiles() * getAltitudinalTiles();
|
return getAzimuthalTiles() * getAltitudinalTiles();
|
||||||
|
@ -45,14 +40,14 @@ namespace starfield {
|
||||||
}
|
}
|
||||||
|
|
||||||
float getSliceAngle() const {
|
float getSliceAngle() const {
|
||||||
return 1.0f / _valRcpSlice;
|
return 1.0f / _rcpSlice;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
unsigned discreteAngle(float unsigned_angle) const {
|
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 {
|
unsigned discreteAzimuth(float a) const {
|
||||||
|
@ -64,6 +59,11 @@ namespace starfield {
|
||||||
discreteAngle(a + Radians::halfPi()) );
|
discreteAngle(a + Radians::halfPi()) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// variables
|
||||||
|
|
||||||
|
unsigned _valK;
|
||||||
|
float _rcpSlice;
|
||||||
|
unsigned _nBits;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
|
@ -25,25 +25,26 @@ namespace starfield {
|
||||||
*/
|
*/
|
||||||
class VertexOrder : public Radix2IntegerScanner<unsigned>
|
class VertexOrder : public Radix2IntegerScanner<unsigned>
|
||||||
{
|
{
|
||||||
Tiling _objTiling;
|
|
||||||
|
|
||||||
typedef Radix2IntegerScanner<unsigned> base;
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
explicit VertexOrder(Tiling const& tiling) :
|
explicit VertexOrder(Tiling const& tiling) :
|
||||||
|
|
||||||
base(tiling.getTileIndexBits() + BrightnessBits),
|
base(tiling.getTileIndexBits() + BrightnessBits),
|
||||||
_objTiling(tiling) {
|
_tiling(tiling) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool bit(InputVertex const& v, state_type const& s) const {
|
bool bit(InputVertex const& v, state_type const& s) const {
|
||||||
|
|
||||||
// inspect (tile_index, brightness) tuples
|
// inspect (tile_index, brightness) tuples
|
||||||
unsigned key = getBrightness(v.getColor()) ^ BrightnessMask;
|
unsigned key = getBrightness(v.getColor()) ^ BrightnessMask;
|
||||||
key |= _objTiling.getTileIndex(
|
key |= _tiling.getTileIndex(
|
||||||
v.getAzimuth(), v.getAltitude()) << BrightnessBits;
|
v.getAzimuth(), v.getAltitude()) << BrightnessBits;
|
||||||
return base::bit(key, s);
|
return base::bit(key, s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
Tiling _tiling;
|
||||||
|
|
||||||
|
typedef Radix2IntegerScanner<unsigned> base;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
} // anonymous namespace
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include <QImage>
|
#include <QImage>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
|
#include "InterfaceConfig.h"
|
||||||
|
|
||||||
// a special "character" that renders as a solid block
|
// a special "character" that renders as a solid block
|
||||||
const char SOLID_BLOCK_CHAR = 127;
|
const char SOLID_BLOCK_CHAR = 127;
|
||||||
|
|
||||||
|
|
|
@ -14,10 +14,8 @@
|
||||||
#include <PacketHeaders.h>
|
#include <PacketHeaders.h>
|
||||||
|
|
||||||
#include "AvatarData.h"
|
#include "AvatarData.h"
|
||||||
#include "avatars_Log.h"
|
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
using avatars_lib::printLog;
|
|
||||||
|
|
||||||
int packFloatAngleToTwoByte(unsigned char* buffer, float angle) {
|
int packFloatAngleToTwoByte(unsigned char* buffer, float angle) {
|
||||||
const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.0);
|
const float ANGLE_CONVERSION_RATIO = (std::numeric_limits<uint16_t>::max() / 360.0);
|
||||||
|
@ -236,4 +234,4 @@ int AvatarData::parseData(unsigned char* sourceBuffer, int numBytes) {
|
||||||
_wantDelta = oneAtBit(wantItems,WANT_DELTA_AT_BIT);
|
_wantDelta = oneAtBit(wantItems,WANT_DELTA_AT_BIT);
|
||||||
|
|
||||||
return sourceBuffer - startPosition;
|
return sourceBuffer - startPosition;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,9 +7,6 @@
|
||||||
|
|
||||||
#include "Orientation.h"
|
#include "Orientation.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
//#include "avatars_Log.h"
|
|
||||||
|
|
||||||
//using avatars_lib::printLog;
|
|
||||||
|
|
||||||
static const bool USING_QUATERNIONS = true;
|
static const bool USING_QUATERNIONS = true;
|
||||||
|
|
||||||
|
|
|
@ -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 <cstdio>
|
|
||||||
|
|
||||||
namespace avatars_lib {
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int (* printLog)(char const*, ...) = & printf;
|
|
||||||
}
|
|
|
@ -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__) */
|
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
#include "Agent.h"
|
#include "Agent.h"
|
||||||
#include "AgentTypes.h"
|
#include "AgentTypes.h"
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "shared_Log.h"
|
#include "Log.h"
|
||||||
#include "UDPSocket.h"
|
#include "UDPSocket.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
|
@ -20,8 +20,6 @@
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using shared_lib::printLog;
|
|
||||||
|
|
||||||
int unpackAgentId(unsigned char* packedData, uint16_t* agentId) {
|
int unpackAgentId(unsigned char* packedData, uint16_t* agentId) {
|
||||||
memcpy(agentId, packedData, sizeof(uint16_t));
|
memcpy(agentId, packedData, sizeof(uint16_t));
|
||||||
return sizeof(uint16_t);
|
return sizeof(uint16_t);
|
||||||
|
@ -150,4 +148,4 @@ void Agent::printLog(Agent const& agent) {
|
||||||
agent._type,
|
agent._type,
|
||||||
publicAddressBuffer,
|
publicAddressBuffer,
|
||||||
publicAddressPort);
|
publicAddressPort);
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@
|
||||||
#include "AgentTypes.h"
|
#include "AgentTypes.h"
|
||||||
#include "PacketHeaders.h"
|
#include "PacketHeaders.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
#include "shared_Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Syssocket.h"
|
#include "Syssocket.h"
|
||||||
|
@ -23,8 +23,6 @@
|
||||||
#include <arpa/inet.h>
|
#include <arpa/inet.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using shared_lib::printLog;
|
|
||||||
|
|
||||||
const char SOLO_AGENT_TYPES[3] = {
|
const char SOLO_AGENT_TYPES[3] = {
|
||||||
AGENT_TYPE_AVATAR_MIXER,
|
AGENT_TYPE_AVATAR_MIXER,
|
||||||
AGENT_TYPE_AUDIO_MIXER,
|
AGENT_TYPE_AUDIO_MIXER,
|
||||||
|
|
|
@ -1,17 +1,15 @@
|
||||||
//
|
//
|
||||||
// voxels_Log.cpp
|
// Log.cpp
|
||||||
// hifi
|
// hifi
|
||||||
//
|
//
|
||||||
// Created by Tobias Schwinger on 4/17/13.
|
// Created by Tobias Schwinger on 4/17/13.
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "voxels_Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
namespace voxels_lib {
|
using namespace std;
|
||||||
using namespace std;
|
int (* printLog)(char const*, ...) = & printf;
|
||||||
|
|
||||||
int (* printLog)(char const*, ...) = & printf;
|
|
||||||
}
|
|
|
@ -1,5 +1,5 @@
|
||||||
//
|
//
|
||||||
// shared_Log.h
|
// Log.h
|
||||||
// hifi
|
// hifi
|
||||||
//
|
//
|
||||||
// Created by Tobias Schwinger on 4/17/13.
|
// Created by Tobias Schwinger on 4/17/13.
|
||||||
|
@ -9,12 +9,13 @@
|
||||||
#ifndef __hifi__shared_Log__
|
#ifndef __hifi__shared_Log__
|
||||||
#define __hifi__shared_Log__
|
#define __hifi__shared_Log__
|
||||||
|
|
||||||
namespace shared_lib {
|
//
|
||||||
|
// Pointer to log function
|
||||||
// variable that can be set from outside to redirect the log output
|
//
|
||||||
// of this library
|
// An application may reset this variable to receive the log messages
|
||||||
extern int (* printLog)(char const*, ...);
|
// issued using 'printLog'. It defaults to a pointer to 'printf'.
|
||||||
}
|
//
|
||||||
|
extern int (* printLog)(char const*, ...);
|
||||||
|
|
||||||
#endif /* defined(__hifi__shared_Log__) */
|
#endif /* defined(__hifi__shared_Log__) */
|
||||||
|
|
|
@ -11,9 +11,7 @@
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
#include "OctalCode.h"
|
#include "OctalCode.h"
|
||||||
#include "shared_Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
using shared_lib::printLog;
|
|
||||||
|
|
||||||
int numberOfThreeBitSectionsInCode(unsigned char * octalCode) {
|
int numberOfThreeBitSectionsInCode(unsigned char * octalCode) {
|
||||||
if (*octalCode == 255) {
|
if (*octalCode == 255) {
|
||||||
|
|
|
@ -14,9 +14,7 @@
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "shared_Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
using shared_lib::printLog;
|
|
||||||
|
|
||||||
// Static class members initialization here!
|
// Static class members initialization here!
|
||||||
std::map<std::string,PerfStatHistory,std::less<std::string> > PerfStat::groupHistoryMap;
|
std::map<std::string,PerfStatHistory,std::less<std::string> > PerfStat::groupHistoryMap;
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include "Syssocket.h"
|
#include "Syssocket.h"
|
||||||
#endif
|
#endif
|
||||||
#include "shared_Log.h"
|
#include "Log.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
#include "OctalCode.h"
|
#include "OctalCode.h"
|
||||||
|
|
||||||
|
@ -22,8 +22,6 @@
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
using shared_lib::printLog;
|
|
||||||
|
|
||||||
double usecTimestamp(timeval *time) {
|
double usecTimestamp(timeval *time) {
|
||||||
return (time->tv_sec * 1000000.0 + time->tv_usec);
|
return (time->tv_sec * 1000000.0 + time->tv_usec);
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,9 +21,7 @@
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "shared_Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
using shared_lib::printLog;
|
|
||||||
|
|
||||||
sockaddr_in destSockaddr, senderAddress;
|
sockaddr_in destSockaddr, senderAddress;
|
||||||
|
|
||||||
|
|
|
@ -10,121 +10,166 @@
|
||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#define NOCURL_IN_WINDOWS
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
#ifndef NOCURL_IN_WINDOWS
|
#include "Log.h"
|
||||||
#include <curl/curl.h>
|
|
||||||
size_t const UrlReader::max_read_ahead = CURL_MAX_WRITE_SIZE;
|
|
||||||
#else
|
|
||||||
size_t const UrlReader::max_read_ahead = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
char const* const UrlReader::success = "UrlReader: Success!";
|
#ifndef _WIN32
|
||||||
char const* const UrlReader::success_cached = "UrlReader:: Using local file.";
|
// (Windows port is incomplete and the build files do not support CURL, yet)
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// 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_init_failed = "UrlReader: Initialization failed.";
|
||||||
char const* const UrlReader::error_aborted = "UrlReader: Processing error.";
|
char const* const UrlReader::error_aborted = "UrlReader: Processing error.";
|
||||||
char const* const UrlReader::error_buffer_overflow = "UrlReader: Buffer overflow.";
|
char const* const UrlReader::error_buffer_overflow = "UrlReader: Buffer overflow.";
|
||||||
char const* const UrlReader::error_leftover_input = "UrlReader: Incomplete processing.";
|
char const* const UrlReader::error_leftover_input = "UrlReader: Incomplete processing.";
|
||||||
|
|
||||||
#define hnd_curl static_cast<CURL*>(_ptrImpl)
|
#define _curlPtr static_cast<CURL*>(_curlHandle)
|
||||||
|
|
||||||
UrlReader::UrlReader()
|
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];
|
_xtraBuffer = new(std::nothrow) char[max_read_ahead];
|
||||||
if (! _arrXtra) { _strError = error_init_failed; return; }
|
if (! _xtraBuffer) { _errorStr = error_init_failed; return; }
|
||||||
#ifndef NOCURL_IN_WINDOWS
|
_curlHandle = curl_easy_init();
|
||||||
_ptrImpl = curl_easy_init();
|
if (! _curlHandle) { _errorStr = error_init_failed; return; }
|
||||||
if (! _ptrImpl) { _strError = error_init_failed; return; }
|
curl_easy_setopt(_curlPtr, CURLOPT_NOSIGNAL, 1l);
|
||||||
curl_easy_setopt(hnd_curl, CURLOPT_NOSIGNAL, 1l);
|
curl_easy_setopt(_curlPtr, CURLOPT_FAILONERROR, 1l);
|
||||||
curl_easy_setopt(hnd_curl, CURLOPT_FAILONERROR, 1l);
|
curl_easy_setopt(_curlPtr, CURLOPT_FILETIME, 1l);
|
||||||
curl_easy_setopt(hnd_curl, CURLOPT_FILETIME, 1l);
|
curl_easy_setopt(_curlPtr, CURLOPT_ENCODING, "");
|
||||||
curl_easy_setopt(hnd_curl, CURLOPT_ENCODING, "");
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UrlReader::~UrlReader() {
|
UrlReader::~UrlReader() {
|
||||||
|
|
||||||
delete[] _arrXtra;
|
delete[] _xtraBuffer;
|
||||||
delete[] _arrCacheRdBuf;
|
delete[] _cacheReadBuffer;
|
||||||
#ifndef NOCURL_IN_WINDOWS
|
if (! _curlHandle) {
|
||||||
if (! hnd_curl) return;
|
return;
|
||||||
curl_easy_cleanup(hnd_curl);
|
}
|
||||||
#endif
|
curl_easy_cleanup(_curlPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UrlReader::perform(char const* url, transfer_callback* cb) {
|
void UrlReader::perform(char const* url, transfer_callback* cb) {
|
||||||
#ifndef NOCURL_IN_WINDOWS
|
|
||||||
|
|
||||||
curl_easy_setopt(hnd_curl, CURLOPT_URL, url);
|
curl_easy_setopt(_curlPtr, CURLOPT_URL, url);
|
||||||
curl_easy_setopt(hnd_curl, CURLOPT_WRITEFUNCTION, cb);
|
curl_easy_setopt(_curlPtr, CURLOPT_WRITEFUNCTION, cb);
|
||||||
curl_easy_setopt(hnd_curl, CURLOPT_WRITEDATA, this);
|
curl_easy_setopt(_curlPtr, CURLOPT_WRITEDATA, this);
|
||||||
|
|
||||||
CURLcode rc = curl_easy_perform(hnd_curl);
|
CURLcode rc = curl_easy_perform(_curlPtr);
|
||||||
|
|
||||||
if (rc == CURLE_OK)
|
if (rc == CURLE_OK)
|
||||||
{
|
{
|
||||||
while (_valXtraSize > 0 && _strError == success)
|
while (_xtraSize > 0 && _errorStr == success)
|
||||||
cb(0l, 0, 0, this);
|
cb(0l, 0, 0, this);
|
||||||
}
|
}
|
||||||
else if (_strError == success)
|
else if (_errorStr == success)
|
||||||
_strError = curl_easy_strerror(rc);
|
_errorStr = curl_easy_strerror(rc);
|
||||||
|
|
||||||
return rc == CURLE_OK;
|
|
||||||
#else
|
|
||||||
return false;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void UrlReader::getinfo(char const*& url,
|
void UrlReader::transferBegin(void* stream, char const* cacheFile) {
|
||||||
char const*& type, int64_t& length, int64_t& stardate) {
|
|
||||||
#ifndef NOCURL_IN_WINDOWS
|
|
||||||
|
|
||||||
|
_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;
|
double clen;
|
||||||
long time;
|
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<int64_t>(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
|
// check caching file time whether we actually want to download anything
|
||||||
if (_strCacheFile != 0l) {
|
if (_cacheFileName != 0l) {
|
||||||
struct stat s;
|
struct stat s;
|
||||||
stat(_strCacheFile, & s);
|
stat(_cacheFileName, & s);
|
||||||
if (time > s.st_mtime) {
|
if (time > s.st_mtime) {
|
||||||
// file on server is newer -> update cache file
|
// file on server is newer -> update cache file
|
||||||
_ptrCacheFile = fopen(_strCacheFile, "wb");
|
_cacheFile = fopen(_cacheFileName, "wb");
|
||||||
printf("From URL: ");
|
// printLog("UrlReader: Also writing content to cache file '%s'\n", _cacheFileName);
|
||||||
if (_ptrCacheFile != 0l) {
|
if (_cacheFile != 0l) {
|
||||||
_valCacheMode = cache_write;
|
_cacheMode = cache_write;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// file on server is older -> use cache file
|
// file on server is older -> use cache file
|
||||||
if (! _arrCacheRdBuf) {
|
if (! _cacheReadBuffer) {
|
||||||
_arrCacheRdBuf = new (std::nothrow) char[max_read_ahead];
|
_cacheReadBuffer = new (std::nothrow) char[max_read_ahead];
|
||||||
if (! _arrCacheRdBuf) {
|
if (! _cacheReadBuffer) {
|
||||||
_valCacheMode = no_cache;
|
// out of memory, no caching, have CURL catch it
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ptrCacheFile = fopen(_strCacheFile, "rb");
|
_cacheFile = fopen(_cacheFileName, "rb");
|
||||||
printf("From file: ");
|
// printLog("UrlReader: Delivering cached content from file '%s'\n", _cacheFileName);
|
||||||
if (_ptrCacheFile != 0l) {
|
if (_cacheFile != 0l) {
|
||||||
_valCacheMode = cache_read;
|
_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<int64_t>(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
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,177 +19,190 @@
|
||||||
// via URLs. Use one per thread.
|
// via URLs. Use one per thread.
|
||||||
//
|
//
|
||||||
class UrlReader {
|
class UrlReader {
|
||||||
|
public:
|
||||||
|
|
||||||
enum CacheMode { no_cache, cache_write, cache_read };
|
//
|
||||||
|
// Constructor - performs initialization, never throws.
|
||||||
|
//
|
||||||
|
UrlReader();
|
||||||
|
|
||||||
void* _ptrImpl;
|
//
|
||||||
char* _arrXtra;
|
// Destructor - frees resources, never throws.
|
||||||
char const* _strError;
|
//
|
||||||
void* _ptrStream;
|
~UrlReader();
|
||||||
char const* _strCacheFile;
|
|
||||||
FILE* _ptrCacheFile;
|
|
||||||
char* _arrCacheRdBuf;
|
|
||||||
CacheMode _valCacheMode;
|
|
||||||
size_t _valXtraSize;
|
|
||||||
public:
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Constructor - performs initialization, never throws.
|
// Reads data from an URL and forwards it to the instance of a class
|
||||||
//
|
// fulfilling the ContentStream concept.
|
||||||
UrlReader();
|
//
|
||||||
|
// 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.
|
// Returns a pointer to a static C-string that describes the error
|
||||||
//
|
// condition.
|
||||||
~UrlReader();
|
//
|
||||||
|
inline char const* getError() const;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Reads data from an URL and forwards it to the instance of a class
|
// Can be called by the stream to set a user-defined error string.
|
||||||
// fulfilling the ContentStream concept.
|
//
|
||||||
//
|
inline void setError(char const* static_c_string);
|
||||||
// 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);
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Returns a pointer to a static C-string that describes the error
|
// Pointer to the C-string returned by a call to 'readUrl' when no
|
||||||
// condition.
|
// error occurred.
|
||||||
//
|
//
|
||||||
inline char const* getError() const;
|
static char const* const success;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Can be called by the stream to set a user-defined error 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
|
||||||
inline void setError(char const* static_c_string);
|
// network stream.
|
||||||
|
//
|
||||||
|
static char const* const success_cached;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Pointer to the C-string returned by a call to 'readUrl' when no
|
// Pointer to the C-string returned by a call to 'readUrl' when the
|
||||||
// error occurred.
|
// initialization has failed.
|
||||||
//
|
//
|
||||||
static char const* const success;
|
static char const* const error_init_failed;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Pointer to the C-string returned by a call to 'readUrl' when no
|
// Pointer to the C-string returned by a call to 'readUrl' when the
|
||||||
// error occurred and a local file has been read instead of the
|
// transfer has been aborted by the client.
|
||||||
// network stream.
|
//
|
||||||
//
|
static char const* const error_aborted;
|
||||||
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
|
// Pointer to the C-string returned by a call to 'readUrl' when
|
||||||
// transfer has been aborted by the client.
|
// leftover input from incomplete processing caused a buffer
|
||||||
//
|
// overflow.
|
||||||
static char const* const error_aborted;
|
//
|
||||||
|
static char const* const error_buffer_overflow;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Pointer to the C-string returned by a call to 'readUrl' when
|
// Pointer to the C-string return by a call to 'readUrl' when the
|
||||||
// leftover input from incomplete processing caused a buffer
|
// input provided was not completely consumed.
|
||||||
// overflow.
|
//
|
||||||
//
|
static char const* const error_leftover_input;
|
||||||
static char const* const error_buffer_overflow;
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Pointer to the C-string return by a call to 'readUrl' when the
|
// Constant of the maximum number of bytes that are buffered
|
||||||
// input provided was not completely consumed.
|
// between invocations of 'transfer'.
|
||||||
//
|
//
|
||||||
static char const* const error_leftover_input;
|
static size_t const max_read_ahead;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Constant of the maximum number of bytes that are buffered
|
// Constant representing absent information in the call to the
|
||||||
// between invocations of 'transfer'.
|
// 'begin' member function of the target stream.
|
||||||
//
|
//
|
||||||
static size_t const max_read_ahead;
|
static int const unavailable = -1;
|
||||||
|
|
||||||
//
|
//
|
||||||
// Constant representing absent information in the call to the
|
// Constant for requesting to abort the current transfer when
|
||||||
// 'begin' member function of the target stream.
|
// returned by the 'transfer' member function of the target stream.
|
||||||
//
|
//
|
||||||
static int const unavailable = -1;
|
static size_t const abort = ~0u;
|
||||||
|
|
||||||
//
|
private:
|
||||||
// Constant for requesting to abort the current transfer when
|
// instances of this class shall not be copied
|
||||||
// returned by the 'transfer' member function of the target stream.
|
UrlReader(UrlReader const&); // = delete;
|
||||||
//
|
UrlReader& operator=(UrlReader const&); // = delete;
|
||||||
static size_t const abort = ~0u;
|
|
||||||
|
|
||||||
private:
|
inline bool isSuccess();
|
||||||
// instances of this class shall not be copied
|
|
||||||
UrlReader(UrlReader const&); // = delete;
|
|
||||||
UrlReader& operator=(UrlReader const&); // = delete;
|
|
||||||
|
|
||||||
// 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,
|
void transferBegin(void* stream, char const* cacheFile);
|
||||||
char const*& type, int64_t& length, int64_t& stardate);
|
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,
|
void getInfo(char const*& url,
|
||||||
size_t nmemb, void* thiz);
|
char const*& type, int64_t& length, int64_t& stardate);
|
||||||
|
|
||||||
template< class Stream > size_t feedBuffered(Stream* stream,
|
// synthesized callback
|
||||||
char* input, size_t size);
|
|
||||||
|
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 >
|
template< class ContentStream >
|
||||||
bool UrlReader::readUrl(char const* url, ContentStream& s, char const* cacheFile) {
|
bool UrlReader::readUrl(char const* url, ContentStream& s, char const* cacheFile) {
|
||||||
if (! _ptrImpl) return false;
|
if (! _curlHandle) 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<ContentStream>);
|
|
||||||
s.end(_strError == success);
|
|
||||||
if (_ptrCacheFile != 0l) {
|
|
||||||
fclose(_ptrCacheFile);
|
|
||||||
}
|
|
||||||
return _strError == success || _strError == success_cached;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline char const* UrlReader::getError() const { return this->_strError; }
|
this->transferBegin(& s, cacheFile);
|
||||||
|
this->perform(url, & callback_template<ContentStream>);
|
||||||
|
this->transferEnd();
|
||||||
|
bool ok = isSuccess();
|
||||||
|
s.end(ok);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
inline void UrlReader::setError(char const* staticCstring) {
|
inline void UrlReader::setError(char const* staticCstring) {
|
||||||
|
|
||||||
if (this->_strError == success || this->_strError == success_cached)
|
if (this->isSuccess())
|
||||||
this->_strError = staticCstring;
|
this->_errorStr = staticCstring;
|
||||||
}
|
}
|
||||||
|
|
||||||
template< class Stream >
|
template< class Stream >
|
||||||
size_t UrlReader::feedBuffered(Stream* stream, char* input, size_t size) {
|
size_t UrlReader::feedBuffered(Stream* stream, char* input, size_t size) {
|
||||||
|
|
||||||
size_t inputOffset = 0u;
|
size_t inputOffset = 0u;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
@ -198,15 +211,15 @@ size_t UrlReader::feedBuffered(Stream* stream, char* input, size_t size) {
|
||||||
size_t bytes = size - inputOffset;
|
size_t bytes = size - inputOffset;
|
||||||
|
|
||||||
// data in extra buffer?
|
// data in extra buffer?
|
||||||
if (_valXtraSize > 0) {
|
if (_xtraSize > 0) {
|
||||||
|
|
||||||
// fill extra buffer with beginning of input
|
// 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;
|
if (bytes < fill) fill = bytes;
|
||||||
memcpy(_arrXtra + _valXtraSize, buffer, fill);
|
memcpy(_xtraBuffer + _xtraSize, buffer, fill);
|
||||||
// use extra buffer for next transfer
|
// use extra buffer for next transfer
|
||||||
buffer = _arrXtra;
|
buffer = _xtraBuffer;
|
||||||
bytes = _valXtraSize + fill;
|
bytes = _xtraSize + fill;
|
||||||
inputOffset += fill;
|
inputOffset += fill;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -225,9 +238,9 @@ size_t UrlReader::feedBuffered(Stream* stream, char* input, size_t size) {
|
||||||
size_t unprocessed = bytes - processed;
|
size_t unprocessed = bytes - processed;
|
||||||
|
|
||||||
// can switch to input buffer, now?
|
// can switch to input buffer, now?
|
||||||
if (buffer == _arrXtra && unprocessed <= inputOffset) {
|
if (buffer == _xtraBuffer && unprocessed <= inputOffset) {
|
||||||
|
|
||||||
_valXtraSize = 0u;
|
_xtraSize = 0u;
|
||||||
inputOffset -= unprocessed;
|
inputOffset -= unprocessed;
|
||||||
|
|
||||||
} else { // no? unprocessed data -> extra buffer
|
} 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);
|
setError(error_buffer_overflow);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
_valXtraSize = unprocessed;
|
_xtraSize = unprocessed;
|
||||||
memmove(_arrXtra, buffer + processed, unprocessed);
|
memmove(_xtraBuffer, buffer + processed, unprocessed);
|
||||||
|
|
||||||
if (inputOffset == size || buffer != _arrXtra) {
|
if (inputOffset == size || buffer != _xtraBuffer) {
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
@ -253,18 +266,18 @@ size_t UrlReader::callback_template(char *input, size_t size, size_t nmemb, void
|
||||||
|
|
||||||
size_t result = 0u;
|
size_t result = 0u;
|
||||||
UrlReader* me = static_cast<UrlReader*>(thiz);
|
UrlReader* me = static_cast<UrlReader*>(thiz);
|
||||||
Stream* stream = static_cast<Stream*>(me->_ptrStream);
|
Stream* stream = static_cast<Stream*>(me->_streamPtr);
|
||||||
size *= nmemb;
|
size *= nmemb;
|
||||||
|
|
||||||
// first call?
|
// 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'
|
// extract meta information and call 'begin'
|
||||||
char const* url, * type;
|
char const* url, * type;
|
||||||
int64_t length, stardate;
|
int64_t length, stardate;
|
||||||
me->getinfo(url, type, length, stardate);
|
me->getInfo(url, type, length, stardate);
|
||||||
if (me->_valCacheMode != cache_read) {
|
if (me->_cacheMode != cache_read) {
|
||||||
stream->begin(url, type, length, stardate);
|
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
|
// will have to repeat from here when reading a local file
|
||||||
|
|
||||||
// read from cache file?
|
// read from cache file?
|
||||||
if (me->_valCacheMode == cache_read) {
|
if (me->_cacheMode == cache_read) {
|
||||||
// change input buffer and start
|
// change input buffer and start
|
||||||
input = me->_arrCacheRdBuf;
|
input = me->_cacheReadBuffer;
|
||||||
size = fread(input, 1, max_read_ahead, me->_ptrCacheFile);
|
size = fread(input, 1, max_read_ahead, me->_cacheFile);
|
||||||
nmemb = 1;
|
nmemb = 1;
|
||||||
} else if (me->_valCacheMode == cache_write) {
|
} else if (me->_cacheMode == cache_write) {
|
||||||
fwrite(input, 1, size, me->_ptrCacheFile);
|
fwrite(input, 1, size, me->_cacheFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
result = me->feedBuffered(stream, input, size);
|
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__) */
|
#endif /* defined(__hifi__UrlReader__) */
|
||||||
|
|
|
@ -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 <cstdio>
|
|
||||||
|
|
||||||
namespace shared_lib {
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
int (* printLog)(char const*, ...) = & printf;
|
|
||||||
}
|
|
|
@ -9,11 +9,10 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
#include "Plane.h"
|
#include "Plane.h"
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
#include "voxels_Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
using voxels_lib::printLog;
|
|
||||||
|
|
||||||
// These are some useful utilities that vec3 is missing
|
// These are some useful utilities that vec3 is missing
|
||||||
void printVec3(const char* name, const glm::vec3& v) {
|
void printVec3(const char* name, const glm::vec3& v) {
|
||||||
|
|
|
@ -14,9 +14,8 @@
|
||||||
|
|
||||||
#include "ViewFrustum.h"
|
#include "ViewFrustum.h"
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
#include "voxels_Log.h"
|
#include "Log.h"
|
||||||
|
|
||||||
using voxels_lib::printLog;
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
ViewFrustum::ViewFrustum() :
|
ViewFrustum::ViewFrustum() :
|
||||||
|
|
|
@ -10,14 +10,11 @@
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
#include "voxels_Log.h"
|
#include "Log.h"
|
||||||
#include "VoxelNode.h"
|
#include "VoxelNode.h"
|
||||||
#include "VoxelConstants.h"
|
#include "VoxelConstants.h"
|
||||||
#include "OctalCode.h"
|
#include "OctalCode.h"
|
||||||
#include "AABox.h"
|
#include "AABox.h"
|
||||||
using voxels_lib::printLog;
|
|
||||||
|
|
||||||
// using voxels_lib::printLog;
|
|
||||||
|
|
||||||
VoxelNode::VoxelNode() {
|
VoxelNode::VoxelNode() {
|
||||||
unsigned char* rootCode = new unsigned char[1];
|
unsigned char* rootCode = new unsigned char[1];
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include "SharedUtil.h"
|
#include "SharedUtil.h"
|
||||||
#include "voxels_Log.h"
|
#include "Log.h"
|
||||||
#include "PacketHeaders.h"
|
#include "PacketHeaders.h"
|
||||||
#include "OctalCode.h"
|
#include "OctalCode.h"
|
||||||
#include "VoxelTree.h"
|
#include "VoxelTree.h"
|
||||||
|
@ -24,8 +24,6 @@
|
||||||
|
|
||||||
#include <glm/gtc/noise.hpp>
|
#include <glm/gtc/noise.hpp>
|
||||||
|
|
||||||
using voxels_lib::printLog;
|
|
||||||
|
|
||||||
int boundaryDistanceForRenderLevel(unsigned int renderLevel) {
|
int boundaryDistanceForRenderLevel(unsigned int renderLevel) {
|
||||||
float voxelSizeScale = 50000.0f;
|
float voxelSizeScale = 50000.0f;
|
||||||
return voxelSizeScale / powf(2, renderLevel);
|
return voxelSizeScale / powf(2, renderLevel);
|
||||||
|
|
|
@ -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__) */
|
|
||||||
|
|
Loading…
Reference in a new issue