mirror of
https://github.com/overte-org/overte.git
synced 2025-08-06 15:59:49 +02:00
Starfield modification to randomly generate stars
Starfield now generates stars at startup rather than load them from the server - approx. 50msec to load 50,000 stars. STAR_COLORIZATION const in Generator.cpp is used to defined how colorful the stars should be. STARFIELD_NUM_STARS and STARFIELD_SEED sets the number of stars and the random number seed used to generate the starfield.
This commit is contained in:
parent
7d7f2d35d0
commit
25d5b38f5f
20 changed files with 658 additions and 1102 deletions
|
@ -72,8 +72,8 @@
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
// Starfield information
|
// Starfield information
|
||||||
static char STAR_FILE[] = "http://s3-us-west-1.amazonaws.com/highfidelity/stars.txt";
|
static unsigned STARFIELD_NUM_STARS = 50000;
|
||||||
static char STAR_CACHE_FILE[] = "cachedStars.txt";
|
static unsigned STARFIELD_SEED = 1;
|
||||||
|
|
||||||
static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored
|
static const int BANDWIDTH_METER_CLICK_MAX_DRAG_LENGTH = 6; // farther dragged clicks are ignored
|
||||||
|
|
||||||
|
@ -2489,8 +2489,8 @@ void Application::displaySide(Camera& whichCamera) {
|
||||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
|
if (Menu::getInstance()->isOptionChecked(MenuOption::Stars)) {
|
||||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings),
|
||||||
"Application::displaySide() ... stars...");
|
"Application::displaySide() ... stars...");
|
||||||
if (!_stars.getFileLoaded()) {
|
if (!_stars.isStarsLoaded()) {
|
||||||
_stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0);
|
_stars.generate(STARFIELD_NUM_STARS, STARFIELD_SEED);
|
||||||
}
|
}
|
||||||
// should be the first rendering pass - w/o depth buffer / lighting
|
// should be the first rendering pass - w/o depth buffer / lighting
|
||||||
|
|
||||||
|
|
14
interface/src/Stars.cpp
Normal file → Executable file
14
interface/src/Stars.cpp
Normal file → Executable file
|
@ -14,27 +14,23 @@
|
||||||
#undef __interface__Starfield_impl__
|
#undef __interface__Starfield_impl__
|
||||||
|
|
||||||
Stars::Stars() :
|
Stars::Stars() :
|
||||||
_controller(0l), _fileLoaded(false) {
|
_controller(0l), _starsLoaded(false) {
|
||||||
_controller = new starfield::Controller;
|
_controller = new starfield::Controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
Stars::~Stars() {
|
Stars::~Stars() {
|
||||||
delete _controller;
|
delete _controller;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Stars::readInput(const char* url, const char* cacheFile, unsigned limit) {
|
bool Stars::generate(unsigned numStars, unsigned seed) {
|
||||||
_fileLoaded = _controller->readInput(url, cacheFile, limit);
|
_starsLoaded = _controller->computeStars(numStars, seed);
|
||||||
return _fileLoaded;
|
return _starsLoaded;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Stars::setResolution(unsigned k) {
|
bool Stars::setResolution(unsigned k) {
|
||||||
return _controller->setResolution(k);
|
return _controller->setResolution(k);
|
||||||
}
|
}
|
||||||
|
|
||||||
float Stars::changeLOD(float fraction, float overalloc, float 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) {
|
||||||
|
|
||||||
// determine length of screen diagonal from quadrant height and aspect ratio
|
// determine length of screen diagonal from quadrant height and aspect ratio
|
||||||
|
|
36
interface/src/Stars.h
Normal file → Executable file
36
interface/src/Stars.h
Normal file → Executable file
|
@ -21,13 +21,12 @@ class Stars {
|
||||||
Stars();
|
Stars();
|
||||||
~Stars();
|
~Stars();
|
||||||
|
|
||||||
//
|
|
||||||
// Reads input file from URL. Returns true upon success.
|
|
||||||
//
|
//
|
||||||
// The limit parameter allows to reduce the number of stars
|
// Generate stars from random number seed
|
||||||
// that are loaded, keeping the brightest ones.
|
//
|
||||||
//
|
// The numStars parameter sets the number of stars to generate.
|
||||||
bool readInput(const char* url, const char* cacheFile = 0l, unsigned limit = 200000);
|
//
|
||||||
|
bool generate(unsigned numStars, unsigned seed);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Renders the starfield from a local viewer's perspective.
|
// Renders the starfield from a local viewer's perspective.
|
||||||
|
@ -45,27 +44,12 @@ class Stars {
|
||||||
// is returned.
|
// is returned.
|
||||||
//
|
//
|
||||||
bool setResolution(unsigned k);
|
bool setResolution(unsigned k);
|
||||||
|
|
||||||
//
|
|
||||||
// Allows to alter the number of stars to be rendered given a
|
|
||||||
// factor. The least brightest ones are omitted first.
|
|
||||||
//
|
//
|
||||||
// The further parameters determine when GPU resources should
|
// Returns true when stars have been loaded
|
||||||
// be reallocated. Its value is fractional in respect to the
|
|
||||||
// last number of stars 'n' that caused 'n * (1+overalloc)' to
|
|
||||||
// be allocated. When the next call to setLOD causes the total
|
|
||||||
// number of stars that could be rendered to drop below 'n *
|
|
||||||
// (1-realloc)' or rises above 'n * (1+realloc)' GPU resources
|
|
||||||
// are updated. Note that all parameters must be fractions,
|
|
||||||
// that is within the range [0;1] and that 'overalloc' must be
|
|
||||||
// greater than or equal to 'realloc'.
|
|
||||||
//
|
//
|
||||||
// The current level of detail is returned as a float in [0;1].
|
bool isStarsLoaded() const { return _starsLoaded; };
|
||||||
//
|
|
||||||
float changeLOD(float factor,
|
|
||||||
float overalloc = 0.25, float realloc = 0.15);
|
|
||||||
|
|
||||||
bool getFileLoaded() const { return _fileLoaded; };
|
|
||||||
private:
|
private:
|
||||||
// don't copy/assign
|
// don't copy/assign
|
||||||
Stars(Stars const&); // = delete;
|
Stars(Stars const&); // = delete;
|
||||||
|
@ -75,7 +59,7 @@ class Stars {
|
||||||
|
|
||||||
starfield::Controller* _controller;
|
starfield::Controller* _controller;
|
||||||
|
|
||||||
bool _fileLoaded;
|
bool _starsLoaded;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
2
interface/src/starfield/CMakeLists.txt
Normal file → Executable file
2
interface/src/starfield/CMakeLists.txt
Normal file → Executable file
|
@ -4,6 +4,6 @@ project(starfield)
|
||||||
# Only headers (that are facaded by the Stars.cpp file) here -
|
# Only headers (that are facaded by the Stars.cpp file) here -
|
||||||
# hence declared as custom target.
|
# hence declared as custom target.
|
||||||
|
|
||||||
file(GLOB_RECURSE STARFIELD_SRCS *.h)
|
file(GLOB_RECURSE STARFIELD_SRCS *.cpp *.h)
|
||||||
add_custom_target("starfield" SOURCES ${STARFIELD_SRCS})
|
add_custom_target("starfield" SOURCES ${STARFIELD_SRCS})
|
||||||
|
|
||||||
|
|
35
interface/src/starfield/Config.h
Normal file → Executable file
35
interface/src/starfield/Config.h
Normal file → Executable file
|
@ -9,30 +9,6 @@
|
||||||
#ifndef __interface__starfield__Config__
|
#ifndef __interface__starfield__Config__
|
||||||
#define __interface__starfield__Config__
|
#define __interface__starfield__Config__
|
||||||
|
|
||||||
#ifndef __interface__Starfield_impl__
|
|
||||||
#error "This is an implementation file - not intended for direct inclusion."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
|
||||||
// Compile time configuration:
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef STARFIELD_HEMISPHERE_ONLY
|
|
||||||
#define STARFIELD_HEMISPHERE_ONLY 0 // set to 1 for hemisphere only
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef STARFIELD_LOW_MEMORY
|
|
||||||
#define STARFIELD_LOW_MEMORY 0 // set to 1 not to use 16-bit types
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef STARFIELD_DEBUG_CULLING
|
|
||||||
#define STARFIELD_DEBUG_CULLING 0 // set to 1 to peek behind the scenes
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifndef STARFIELD_MULTITHREADING
|
|
||||||
#define STARFIELD_MULTITHREADING 0
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// Dependencies:
|
// Dependencies:
|
||||||
//
|
//
|
||||||
|
@ -49,11 +25,6 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#if STARFIELD_MULTITHREADING
|
|
||||||
#include <mutex>
|
|
||||||
#include <atomic>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <new>
|
#include <new>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
@ -88,14 +59,8 @@ namespace starfield {
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
|
|
||||||
#if STARFIELD_SAVE_MEMORY
|
|
||||||
typedef uint16_t nuint;
|
|
||||||
typedef uint32_t wuint;
|
|
||||||
#else
|
|
||||||
typedef uint32_t nuint;
|
typedef uint32_t nuint;
|
||||||
typedef uint64_t wuint;
|
typedef uint64_t wuint;
|
||||||
#endif
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
63
interface/src/starfield/Controller.cpp
Executable file
63
interface/src/starfield/Controller.cpp
Executable file
|
@ -0,0 +1,63 @@
|
||||||
|
//
|
||||||
|
// starfield/Controller.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Chris Barnard on 10/16/13
|
||||||
|
// Portions of code based on earlier work by Tobias Schwinger.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "starfield/Controller.h"
|
||||||
|
|
||||||
|
using namespace starfield;
|
||||||
|
|
||||||
|
bool Controller::computeStars(unsigned numStars, unsigned seed) {
|
||||||
|
timeval startTime;
|
||||||
|
gettimeofday(&startTime, NULL);
|
||||||
|
|
||||||
|
Generator::computeStarPositions(_inputSequence, numStars, seed);
|
||||||
|
|
||||||
|
this->retile(numStars, _tileResolution);
|
||||||
|
|
||||||
|
qDebug("Total time to generate stars: %llu msec\n", (usecTimestampNow() - usecTimestamp(&startTime)) / 1000);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Controller::setResolution(unsigned tileResolution) {
|
||||||
|
if (tileResolution <= 3) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (tileResolution != _tileResolution) {
|
||||||
|
|
||||||
|
this->retile(_numStars, tileResolution);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::render(float perspective, float angle, mat4 const& orientation, float alpha) {
|
||||||
|
Renderer* renderer = _renderer;
|
||||||
|
|
||||||
|
if (renderer != 0l) {
|
||||||
|
renderer->render(perspective, angle, orientation, alpha);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::retile(unsigned numStars, unsigned tileResolution) {
|
||||||
|
Tiling tiling(tileResolution);
|
||||||
|
VertexOrder scanner(tiling);
|
||||||
|
radix2InplaceSort(_inputSequence.begin(), _inputSequence.end(), scanner);
|
||||||
|
|
||||||
|
recreateRenderer(numStars, tileResolution);
|
||||||
|
|
||||||
|
_tileResolution = tileResolution;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Controller::recreateRenderer(unsigned numStars, unsigned tileResolution) {
|
||||||
|
delete _renderer;
|
||||||
|
_renderer = new Renderer(_inputSequence, numStars, tileResolution);
|
||||||
|
}
|
404
interface/src/starfield/Controller.h
Normal file → Executable file
404
interface/src/starfield/Controller.h
Normal file → Executable file
|
@ -3,52 +3,17 @@
|
||||||
// interface
|
// interface
|
||||||
//
|
//
|
||||||
// Created by Tobias Schwinger on 3/29/13.
|
// Created by Tobias Schwinger on 3/29/13.
|
||||||
|
// Modified by Chris Barnard 10/16/13.
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef __interface__starfield__Controller__
|
#ifndef __interface__starfield__Controller__
|
||||||
#define __interface__starfield__Confroller__
|
#define __interface__starfield__Confroller__
|
||||||
|
|
||||||
#ifndef __interface__Starfield_impl__
|
#include <time.h>
|
||||||
#error "This is an implementation file - not intended for direct inclusion."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
|
||||||
// Data pipeline
|
|
||||||
// =============
|
|
||||||
//
|
|
||||||
// ->> readInput -(load)--+---- (get brightness & sort) ---> brightness LUT
|
|
||||||
// | |
|
|
||||||
// ->> setResolution --+ | >extractBrightnessLevels<
|
|
||||||
// V |
|
|
||||||
// (sort by (tile,brightness))
|
|
||||||
// | |
|
|
||||||
// ->> setLOD ---+ | >retile< ->> setLOD --> (just parameterize
|
|
||||||
// V V when enough data on-GPU)
|
|
||||||
// (filter by max-LOD brightness,
|
|
||||||
// build tile info for rendering)
|
|
||||||
// | |
|
|
||||||
// V >recreateRenderer<
|
|
||||||
// (set new renderer)/
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// (process), ->> entry point, ---> data flow, >internal routine<
|
|
||||||
//
|
|
||||||
// (member functions are ordered by data flow)
|
|
||||||
|
|
||||||
//
|
|
||||||
// Still open
|
|
||||||
// ==========
|
|
||||||
//
|
|
||||||
// o atomics/mutexes need to be added as annotated in the source to allow
|
|
||||||
// concurrent threads to pull the strings to e.g. have a low priority
|
|
||||||
// thread run the data pipeline for update -- rendering is wait-free
|
|
||||||
//
|
|
||||||
|
|
||||||
|
#include "starfield/Generator.h"
|
||||||
#include "starfield/data/InputVertex.h"
|
#include "starfield/data/InputVertex.h"
|
||||||
#include "starfield/data/BrightnessLevel.h"
|
|
||||||
#include "starfield/Loader.h"
|
|
||||||
|
|
||||||
#include "starfield/renderer/Renderer.h"
|
#include "starfield/renderer/Renderer.h"
|
||||||
#include "starfield/renderer/VertexOrder.h"
|
#include "starfield/renderer/VertexOrder.h"
|
||||||
|
|
||||||
|
@ -57,371 +22,30 @@ namespace starfield {
|
||||||
class Controller {
|
class Controller {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Controller() :
|
Controller() : _tileResolution(20), _renderer(0l) { }
|
||||||
_tileResolution(20),
|
|
||||||
_lodFraction(1.0),
|
|
||||||
_lodLowWaterMark(0.8),
|
|
||||||
_lodHighWaterMark(1.0),
|
|
||||||
_lodOveralloc(1.2),
|
|
||||||
_lodNalloc(0),
|
|
||||||
_lodNRender(0),
|
|
||||||
_lodBrightness(0),
|
|
||||||
_lodAllocBrightness(0),
|
|
||||||
_renderer(0l) {
|
|
||||||
}
|
|
||||||
|
|
||||||
~Controller() {
|
~Controller() {
|
||||||
delete _renderer;
|
delete _renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if !STARFIELD_MULTITHREADING
|
|
||||||
#define lock
|
|
||||||
#define _(x)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
bool readInput(const char* url, const char* cacheFile, unsigned limit)
|
|
||||||
{
|
|
||||||
InputVertices vertices;
|
|
||||||
|
|
||||||
if (! Loader().loadVertices(vertices, url, cacheFile, limit))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
BrightnessLevels brightness;
|
|
||||||
extractBrightnessLevels(brightness, vertices);
|
|
||||||
|
|
||||||
// input is read, now run the entire data pipeline on the new input
|
|
||||||
|
|
||||||
{ lock _(_inputMutex);
|
|
||||||
|
|
||||||
_inputSequence.swap(vertices);
|
|
||||||
#if STARFIELD_MULTITHREADING
|
|
||||||
unsigned k = _tileResolution.load(memory_order_relaxed);
|
|
||||||
#else
|
|
||||||
unsigned k = _tileResolution;
|
|
||||||
#endif
|
|
||||||
size_t n, nRender;
|
|
||||||
BrightnessLevel bMin, b;
|
|
||||||
double rcpChange;
|
|
||||||
|
|
||||||
// we'll have to build a new LOD state for a new total N,
|
|
||||||
// ideally keeping allocation size and number of vertices
|
|
||||||
|
|
||||||
{ lock _(_lodStateMutex);
|
|
||||||
|
|
||||||
size_t newLast = _inputSequence.size() - 1;
|
|
||||||
|
|
||||||
// reciprocal change N_old/N_new tells us how to scale
|
|
||||||
// the fractions
|
|
||||||
rcpChange = min(1.0, double(vertices.size()) / _inputSequence.size());
|
|
||||||
|
|
||||||
// initialization? use defaults / previously set values
|
|
||||||
if (rcpChange == 0.0) {
|
|
||||||
|
|
||||||
rcpChange = 1.0;
|
|
||||||
|
|
||||||
nRender = toBufSize(_lodFraction * newLast);
|
|
||||||
n = min(newLast, toBufSize(_lodOveralloc * nRender));
|
|
||||||
|
|
||||||
} else {
|
|
||||||
|
|
||||||
// cannot allocate or render more than we have
|
|
||||||
n = min(newLast, _lodNalloc);
|
|
||||||
nRender = min(newLast, _lodNRender);
|
|
||||||
}
|
|
||||||
|
|
||||||
// determine new minimum brightness levels
|
|
||||||
bMin = brightness[n];
|
|
||||||
b = brightness[nRender];
|
|
||||||
|
|
||||||
// adjust n
|
|
||||||
n = std::upper_bound(
|
|
||||||
brightness.begin() + n - 1,
|
|
||||||
brightness.end(),
|
|
||||||
bMin, GreaterBrightness() ) - brightness.begin();
|
|
||||||
}
|
|
||||||
|
|
||||||
// invoke next stage
|
|
||||||
try {
|
|
||||||
|
|
||||||
this->retile(n, k, b, bMin);
|
|
||||||
|
|
||||||
} catch (...) {
|
|
||||||
|
|
||||||
// rollback transaction and rethrow
|
|
||||||
vertices.swap(_inputSequence);
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
// finally publish the new LOD state
|
|
||||||
|
|
||||||
{ lock _(_lodStateMutex);
|
|
||||||
|
|
||||||
_lodBrightnessSequence.swap(brightness);
|
|
||||||
_lodFraction *= rcpChange;
|
|
||||||
_lodLowWaterMark *= rcpChange;
|
|
||||||
_lodHighWaterMark *= rcpChange;
|
|
||||||
_lodOveralloc *= rcpChange;
|
|
||||||
_lodNalloc = n;
|
|
||||||
_lodNRender = nRender;
|
|
||||||
_lodAllocBrightness = bMin;
|
|
||||||
#if STARFIELD_MULTITHREADING
|
|
||||||
_lodBrightness.store(b, memory_order_relaxed);
|
|
||||||
#else
|
|
||||||
_lodBrightness = b;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool setResolution(unsigned k) {
|
|
||||||
|
|
||||||
if (k <= 3) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// printLog("Stars.cpp: setResolution(%d)\n", k);
|
|
||||||
|
|
||||||
#if STARFIELD_MULTITHREADING
|
|
||||||
if (k != _tileResolution.load(memory_order_relaxed))
|
|
||||||
#else
|
|
||||||
if (k != _tileResolution)
|
|
||||||
#endif
|
|
||||||
{ lock _(_inputMutex);
|
|
||||||
|
|
||||||
unsigned n;
|
|
||||||
BrightnessLevel b, bMin;
|
|
||||||
|
|
||||||
{ lock _(_lodStateMutex);
|
|
||||||
|
|
||||||
n = _lodNalloc;
|
|
||||||
#if STARFIELD_MULTITHREADING
|
|
||||||
b = _lodBrightness.load(memory_order_relaxed);
|
|
||||||
#else
|
|
||||||
b = _lodBrightness;
|
|
||||||
#endif
|
|
||||||
bMin = _lodAllocBrightness;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->retile(n, k, b, bMin);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double changeLOD(double factor, double overalloc, double realloc) {
|
|
||||||
|
|
||||||
assert(overalloc >= realloc && realloc >= 0.0);
|
|
||||||
assert(overalloc <= 1.0 && realloc <= 1.0);
|
|
||||||
|
|
||||||
// printLog(
|
|
||||||
// "Stars.cpp: changeLOD(%lf, %lf, %lf)\n", factor, overalloc, realloc);
|
|
||||||
|
|
||||||
size_t n, nRender;
|
|
||||||
BrightnessLevel bMin, b;
|
|
||||||
double fraction, lwm, hwm;
|
|
||||||
|
|
||||||
{ lock _(_lodStateMutex);
|
|
||||||
|
|
||||||
// acuire a consistent copy of the current LOD state
|
bool computeStars(unsigned numStars, unsigned seed);
|
||||||
fraction = _lodFraction;
|
|
||||||
lwm = _lodLowWaterMark;
|
|
||||||
hwm = _lodHighWaterMark;
|
|
||||||
size_t last = _lodBrightnessSequence.size() - 1;
|
|
||||||
|
|
||||||
// apply factor
|
bool setResolution(unsigned tileResolution);
|
||||||
fraction = max(0.0, min(1.0, fraction * factor));
|
|
||||||
|
|
||||||
// calculate allocation size and corresponding brightness
|
|
||||||
// threshold
|
|
||||||
double oaFract = std::min(fraction * (1.0 + overalloc), 1.0);
|
|
||||||
n = toBufSize(oaFract * last);
|
|
||||||
bMin = _lodBrightnessSequence[n];
|
|
||||||
n = std::upper_bound(
|
|
||||||
_lodBrightnessSequence.begin() + n - 1,
|
|
||||||
_lodBrightnessSequence.end(),
|
|
||||||
bMin, GreaterBrightness() ) - _lodBrightnessSequence.begin();
|
|
||||||
|
|
||||||
// also determine number of vertices to render and brightness
|
void render(float perspective, float angle, mat4 const& orientation, float alpha);
|
||||||
nRender = toBufSize(fraction * last);
|
|
||||||
// Note: nRender does not have to be accurate
|
|
||||||
b = _lodBrightnessSequence[nRender];
|
|
||||||
// this setting controls the renderer, also keep b as the
|
|
||||||
// brightness becomes volatile as soon as the mutex is
|
|
||||||
// released, so keep b
|
|
||||||
#if STARFIELD_MULTITHREADING
|
|
||||||
_lodBrightness.store(b, memory_order_relaxed);
|
|
||||||
#else
|
|
||||||
_lodBrightness = b;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// printLog("Stars.cpp: "
|
|
||||||
// "fraction = %lf, oaFract = %lf, n = %d, n' = %d, bMin = %d, b = %d\n",
|
|
||||||
// fraction, oaFract, toBufSize(oaFract * last)), n, bMin, b);
|
|
||||||
|
|
||||||
// will not have to reallocate? set new fraction right away
|
|
||||||
// (it is consistent with the rest of the state in this case)
|
|
||||||
if (fraction >= _lodLowWaterMark
|
|
||||||
&& fraction <= _lodHighWaterMark) {
|
|
||||||
|
|
||||||
_lodFraction = fraction;
|
|
||||||
return fraction;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// reallocate
|
|
||||||
|
|
||||||
{ lock _(_inputMutex);
|
|
||||||
|
|
||||||
recreateRenderer(n, _tileResolution, b, bMin);
|
|
||||||
|
|
||||||
// printLog("Stars.cpp: LOD reallocation\n");
|
|
||||||
|
|
||||||
// publish new lod state
|
|
||||||
|
|
||||||
{ lock _(_lodStateMutex);
|
|
||||||
|
|
||||||
_lodNalloc = n;
|
|
||||||
_lodNRender = nRender;
|
|
||||||
|
|
||||||
_lodFraction = fraction;
|
|
||||||
_lodLowWaterMark = fraction * (1.0 - realloc);
|
|
||||||
_lodHighWaterMark = fraction * (1.0 + realloc);
|
|
||||||
_lodOveralloc = fraction * (1.0 + overalloc);
|
|
||||||
_lodAllocBrightness = bMin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return fraction;
|
|
||||||
}
|
|
||||||
|
|
||||||
void render(float perspective, float angle, mat4 const& orientation, float alpha) {
|
|
||||||
|
|
||||||
#if STARFIELD_MULTITHREADING
|
|
||||||
// check out renderer
|
|
||||||
Renderer* renderer = _renderer.exchange(0l);
|
|
||||||
#else
|
|
||||||
Renderer* renderer = _renderer;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// have it render
|
|
||||||
if (renderer != 0l) {
|
|
||||||
#if STARFIELD_MULTITHREADING
|
|
||||||
BrightnessLevel b = _lodBrightness.load(memory_order_relaxed);
|
|
||||||
#else
|
|
||||||
BrightnessLevel b = _lodBrightness;
|
|
||||||
#endif
|
|
||||||
renderer->render(perspective, angle, orientation, b, alpha);
|
|
||||||
}
|
|
||||||
|
|
||||||
#if STARFIELD_MULTITHREADING
|
|
||||||
// check in - or dispose if there is a new one
|
|
||||||
Renderer* newOne = 0l;
|
|
||||||
if (! _renderer.compare_exchange_strong(newOne, renderer)) {
|
|
||||||
|
|
||||||
assert(!! newOne);
|
|
||||||
delete renderer;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
# undef lock
|
|
||||||
# undef _
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void retile(size_t n, unsigned k,
|
void retile(unsigned numStars, unsigned tileResolution);
|
||||||
BrightnessLevel b, BrightnessLevel bMin) {
|
|
||||||
|
|
||||||
Tiling tiling(k);
|
void recreateRenderer(unsigned numStars, unsigned tileResolution);
|
||||||
VertexOrder scanner(tiling);
|
|
||||||
radix2InplaceSort(_inputSequence.begin(), _inputSequence.end(), scanner);
|
|
||||||
|
|
||||||
// printLog(
|
InputVertices _inputSequence;
|
||||||
// "Stars.cpp: recreateRenderer(%d, %d, %d, %d)\n", n, k, b, bMin);
|
unsigned _tileResolution;
|
||||||
|
unsigned _numStars;
|
||||||
recreateRenderer(n, k, b, bMin);
|
Renderer* _renderer;
|
||||||
|
|
||||||
_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> {
|
|
||||||
|
|
||||||
typedef Radix2IntegerScanner<BrightnessLevel> base;
|
|
||||||
|
|
||||||
BrightnessSortScanner() : base(BrightnessBits) { }
|
|
||||||
|
|
||||||
bool bit(BrightnessLevel const& k, state_type& s) {
|
|
||||||
|
|
||||||
// bit is inverted to achieve descending order
|
|
||||||
return ! base::bit(k,s);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void extractBrightnessLevels(BrightnessLevels& dst,
|
|
||||||
InputVertices const& src) {
|
|
||||||
dst.clear();
|
|
||||||
dst.reserve(src.size());
|
|
||||||
for (InputVertices::const_iterator i =
|
|
||||||
src.begin(), e = src.end(); i != e; ++i)
|
|
||||||
dst.push_back( getBrightness(i->getColor()) );
|
|
||||||
|
|
||||||
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
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
53
interface/src/starfield/Generator.cpp
Normal file
53
interface/src/starfield/Generator.cpp
Normal file
|
@ -0,0 +1,53 @@
|
||||||
|
//
|
||||||
|
// starfield/Generator.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Chris Barnard on 10/13/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "starfield/Generator.h"
|
||||||
|
|
||||||
|
using namespace starfield;
|
||||||
|
|
||||||
|
const float Generator::STAR_COLORIZATION = 0.1;
|
||||||
|
|
||||||
|
void Generator::computeStarPositions(InputVertices& destination, unsigned limit, unsigned seed) {
|
||||||
|
InputVertices* vertices = & destination;
|
||||||
|
//_limit = limit;
|
||||||
|
|
||||||
|
timeval startTime;
|
||||||
|
gettimeofday(&startTime, NULL);
|
||||||
|
|
||||||
|
srand(seed);
|
||||||
|
|
||||||
|
vertices->clear();
|
||||||
|
vertices->reserve(limit);
|
||||||
|
|
||||||
|
const unsigned NUM_DEGREES = 360;
|
||||||
|
|
||||||
|
|
||||||
|
for(int star = 0; star < limit; ++star) {
|
||||||
|
float azimuth, altitude;
|
||||||
|
azimuth = ((float)rand() / (float) RAND_MAX) * NUM_DEGREES;
|
||||||
|
altitude = (((float)rand() / (float) RAND_MAX) * NUM_DEGREES / 2) - NUM_DEGREES / 4;
|
||||||
|
|
||||||
|
vertices->push_back(InputVertex(azimuth, altitude, computeStarColor(STAR_COLORIZATION)));
|
||||||
|
}
|
||||||
|
|
||||||
|
qDebug("Took %llu msec to generate stars.\n", (usecTimestampNow() - usecTimestamp(&startTime)) / 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// computeStarColor
|
||||||
|
// - Generate a star color.
|
||||||
|
//
|
||||||
|
// colorization can be a value between 0 and 1 specifying how colorful the resulting star color is.
|
||||||
|
//
|
||||||
|
// 0 = completely black & white
|
||||||
|
// 1 = very colorful
|
||||||
|
unsigned Generator::computeStarColor(float colorization) {
|
||||||
|
unsigned char red = rand() % 256;
|
||||||
|
unsigned char green = round((red * (1 - colorization)) + ((rand() % 256) * colorization));
|
||||||
|
unsigned char blue = round((red * (1 - colorization)) + ((rand() % 256) * colorization));
|
||||||
|
return red | green << 8 | blue << 16;
|
||||||
|
}
|
37
interface/src/starfield/Generator.h
Normal file
37
interface/src/starfield/Generator.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
//
|
||||||
|
// starfield/Generator.h
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Chris Barnard on 10/13/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef __interface__starfield__Generator__
|
||||||
|
#define __interface__starfield__Generator__
|
||||||
|
|
||||||
|
#include <locale.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "Config.h"
|
||||||
|
#include "SharedUtil.h"
|
||||||
|
|
||||||
|
#include "starfield/data/InputVertex.h"
|
||||||
|
|
||||||
|
namespace starfield {
|
||||||
|
|
||||||
|
class Generator {
|
||||||
|
|
||||||
|
public:
|
||||||
|
Generator() {}
|
||||||
|
~Generator() {}
|
||||||
|
|
||||||
|
static void computeStarPositions(InputVertices& destination, unsigned limit, unsigned seed);
|
||||||
|
static unsigned computeStarColor(float colorization);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const float STAR_COLORIZATION;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
#endif
|
|
@ -1,64 +0,0 @@
|
||||||
//
|
|
||||||
// starfield/data/BrightnessLevel.h
|
|
||||||
// interface
|
|
||||||
//
|
|
||||||
// Created by Tobias Schwinger on 3/29/13.
|
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
|
||||||
//
|
|
||||||
|
|
||||||
#ifndef __interface__starfield__data__BrightnessLevel__
|
|
||||||
#define __interface__starfield__data__BrightnessLevel__
|
|
||||||
|
|
||||||
#ifndef __interface__Starfield_impl__
|
|
||||||
#error "This is an implementation file - not intended for direct inclusion."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "starfield/Config.h"
|
|
||||||
#include "starfield/data/InputVertex.h"
|
|
||||||
#include "starfield/data/GpuVertex.h"
|
|
||||||
|
|
||||||
namespace starfield {
|
|
||||||
|
|
||||||
typedef nuint BrightnessLevel;
|
|
||||||
|
|
||||||
|
|
||||||
#if STARFIELD_SAVE_MEMORY
|
|
||||||
const unsigned BrightnessBits = 16u;
|
|
||||||
#else
|
|
||||||
const unsigned BrightnessBits = 18u;
|
|
||||||
#endif
|
|
||||||
const BrightnessLevel BrightnessMask = (1u << (BrightnessBits)) - 1u;
|
|
||||||
|
|
||||||
typedef std::vector<BrightnessLevel> BrightnessLevels;
|
|
||||||
|
|
||||||
BrightnessLevel getBrightness(unsigned c) {
|
|
||||||
|
|
||||||
unsigned r = (c >> 16) & 0xff;
|
|
||||||
unsigned g = (c >> 8) & 0xff;
|
|
||||||
unsigned b = c & 0xff;
|
|
||||||
#if STARFIELD_SAVE_MEMORY
|
|
||||||
return BrightnessLevel((r*r+g*g+b*b) >> 2);
|
|
||||||
#else
|
|
||||||
return BrightnessLevel(r*r+g*g+b*b);
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct GreaterBrightness {
|
|
||||||
|
|
||||||
bool operator()(InputVertex const& lhs, InputVertex const& rhs) const {
|
|
||||||
return getBrightness(lhs.getColor())
|
|
||||||
> getBrightness(rhs.getColor());
|
|
||||||
}
|
|
||||||
bool operator()(BrightnessLevel lhs, GpuVertex const& rhs) const {
|
|
||||||
return lhs > getBrightness(rhs.getColor());;
|
|
||||||
}
|
|
||||||
bool operator()(BrightnessLevel lhs, BrightnessLevel rhs) const {
|
|
||||||
return lhs > rhs;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
23
interface/src/starfield/data/GpuVertex.cpp
Executable file
23
interface/src/starfield/data/GpuVertex.cpp
Executable file
|
@ -0,0 +1,23 @@
|
||||||
|
//
|
||||||
|
// starfield/data/GpuVertex.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Chris Barnard on 10/17/13.
|
||||||
|
// Based on code by Tobias Schwinger on 3/29/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
#include "starfield/data/GpuVertex.h"
|
||||||
|
#include "starfield/data/InputVertex.h"
|
||||||
|
|
||||||
|
using namespace starfield;
|
||||||
|
|
||||||
|
GpuVertex::GpuVertex(InputVertex const& inputVertex) {
|
||||||
|
_color = inputVertex.getColor();
|
||||||
|
float azimuth = inputVertex.getAzimuth();
|
||||||
|
float altitude = inputVertex.getAltitude();
|
||||||
|
|
||||||
|
// compute altitude/azimuth into X/Y/Z point on a sphere
|
||||||
|
_valX = sin(azimuth) * cos(altitude);
|
||||||
|
_valY = sin(altitude);
|
||||||
|
_valZ = -cos(azimuth) * cos(altitude);
|
||||||
|
}
|
32
interface/src/starfield/data/GpuVertex.h
Normal file → Executable file
32
interface/src/starfield/data/GpuVertex.h
Normal file → Executable file
|
@ -3,16 +3,13 @@
|
||||||
// interface
|
// interface
|
||||||
//
|
//
|
||||||
// Created by Tobias Schwinger on 3/29/13.
|
// Created by Tobias Schwinger on 3/29/13.
|
||||||
|
// Modified 10/17/13 Chris Barnard.
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef __interface__starfield__data__GpuVertex__
|
#ifndef __interface__starfield__data__GpuVertex__
|
||||||
#define __interface__starfield__data__GpuVertex__
|
#define __interface__starfield__data__GpuVertex__
|
||||||
|
|
||||||
#ifndef __interface__Starfield_impl__
|
|
||||||
#error "This is an implementation file - not intended for direct inclusion."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "starfield/data/InputVertex.h"
|
#include "starfield/data/InputVertex.h"
|
||||||
|
|
||||||
namespace starfield {
|
namespace starfield {
|
||||||
|
@ -21,33 +18,18 @@ namespace starfield {
|
||||||
public:
|
public:
|
||||||
GpuVertex() { }
|
GpuVertex() { }
|
||||||
|
|
||||||
GpuVertex(InputVertex const& in) {
|
GpuVertex(InputVertex const& inputVertex);
|
||||||
|
|
||||||
_color = in.getColor();
|
|
||||||
float azi = in.getAzimuth();
|
|
||||||
float alt = in.getAltitude();
|
|
||||||
|
|
||||||
// ground vector in x/z plane...
|
|
||||||
float gx = sin(azi);
|
|
||||||
float gz = -cos(azi);
|
|
||||||
|
|
||||||
// ...elevated in y direction by altitude
|
|
||||||
float exz = cos(alt);
|
|
||||||
_valX = gx * exz;
|
|
||||||
_valY = sin(alt);
|
|
||||||
_valZ = gz * exz;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned getColor() const { return _color; }
|
unsigned getColor() const { return _color; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned _color;
|
unsigned _color;
|
||||||
float _valX;
|
float _valX;
|
||||||
float _valY;
|
float _valY;
|
||||||
float _valZ;
|
float _valZ;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
24
interface/src/starfield/data/InputVertex.cpp
Executable file
24
interface/src/starfield/data/InputVertex.cpp
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
//
|
||||||
|
// starfield/data/InputVertex.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Chris Barnard on 10/17.13.
|
||||||
|
// Based on code by Tobias Schwinger 3/29/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "starfield/data/InputVertex.h"
|
||||||
|
|
||||||
|
using namespace starfield;
|
||||||
|
|
||||||
|
InputVertex::InputVertex(float azimuth, float altitude, unsigned color) {
|
||||||
|
_color = color | 0xff000000u;
|
||||||
|
|
||||||
|
azimuth = angleConvert<Degrees,Radians>(azimuth);
|
||||||
|
altitude = angleConvert<Degrees,Radians>(altitude);
|
||||||
|
|
||||||
|
angleHorizontalPolar<Radians>(azimuth, altitude);
|
||||||
|
|
||||||
|
_azimuth = azimuth;
|
||||||
|
_altitude = altitude;
|
||||||
|
}
|
27
interface/src/starfield/data/InputVertex.h
Normal file → Executable file
27
interface/src/starfield/data/InputVertex.h
Normal file → Executable file
|
@ -3,16 +3,13 @@
|
||||||
// interface
|
// interface
|
||||||
//
|
//
|
||||||
// Created by Tobias Schwinger on 3/29/13.
|
// Created by Tobias Schwinger on 3/29/13.
|
||||||
|
// Modified by Chris Barnard 10/17/13.
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef __interface__starfield__data__InputVertex__
|
#ifndef __interface__starfield__data__InputVertex__
|
||||||
#define __interface__starfield__data__InputVertex__
|
#define __interface__starfield__data__InputVertex__
|
||||||
|
|
||||||
#ifndef __interface__Starfield_impl__
|
|
||||||
#error "This is an implementation file - not intended for direct inclusion."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "starfield/Config.h"
|
#include "starfield/Config.h"
|
||||||
|
|
||||||
namespace starfield {
|
namespace starfield {
|
||||||
|
@ -20,33 +17,21 @@ namespace starfield {
|
||||||
class InputVertex {
|
class InputVertex {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
InputVertex(float azimuth, float altitude, unsigned color) {
|
InputVertex(float azimuth, float altitude, unsigned color);
|
||||||
|
|
||||||
_color = ((color >> 16) & 0xffu) | (color & 0xff00u) |
|
|
||||||
((color << 16) & 0xff0000u) | 0xff000000u;
|
|
||||||
|
|
||||||
azimuth = angleConvert<Degrees,Radians>(azimuth);
|
|
||||||
altitude = angleConvert<Degrees,Radians>(altitude);
|
|
||||||
|
|
||||||
angleHorizontalPolar<Radians>(azimuth, altitude);
|
|
||||||
|
|
||||||
_azimuth = azimuth;
|
|
||||||
_altitude = altitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
float getAzimuth() const { return _azimuth; }
|
float getAzimuth() const { return _azimuth; }
|
||||||
float getAltitude() const { return _altitude; }
|
float getAltitude() const { return _altitude; }
|
||||||
unsigned getColor() const { return _color; }
|
unsigned getColor() const { return _color; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
unsigned _color;
|
unsigned _color;
|
||||||
float _azimuth;
|
float _azimuth;
|
||||||
float _altitude;
|
float _altitude;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<InputVertex> InputVertices;
|
typedef std::vector<InputVertex> InputVertices;
|
||||||
|
|
||||||
} // anonymous namespace
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
18
interface/src/starfield/data/Tile.h
Normal file → Executable file
18
interface/src/starfield/data/Tile.h
Normal file → Executable file
|
@ -9,30 +9,22 @@
|
||||||
#ifndef __interface__starfield__data__Tile__
|
#ifndef __interface__starfield__data__Tile__
|
||||||
#define __interface__starfield__data__Tile__
|
#define __interface__starfield__data__Tile__
|
||||||
|
|
||||||
#ifndef __interface__Starfield_impl__
|
|
||||||
#error "This is an implementation file - not intended for direct inclusion."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "starfield/Config.h"
|
#include "starfield/Config.h"
|
||||||
#include "starfield/data/BrightnessLevel.h"
|
|
||||||
|
|
||||||
namespace starfield {
|
namespace starfield {
|
||||||
|
|
||||||
struct Tile {
|
struct Tile {
|
||||||
|
nuint offset;
|
||||||
nuint offset;
|
nuint count;
|
||||||
nuint count;
|
nuint flags;
|
||||||
BrightnessLevel lod;
|
|
||||||
nuint flags;
|
|
||||||
|
|
||||||
// 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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
}
|
||||||
} // anonymous namespace
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
311
interface/src/starfield/renderer/Renderer.cpp
Executable file
311
interface/src/starfield/renderer/Renderer.cpp
Executable file
|
@ -0,0 +1,311 @@
|
||||||
|
//
|
||||||
|
// starfield/renderer/Renderer.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Chris Barnard on 10/17/13.
|
||||||
|
// Based on earlier work by Tobias Schwinger 3/22/13.
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "starfield/renderer/Renderer.h"
|
||||||
|
|
||||||
|
using namespace starfield;
|
||||||
|
|
||||||
|
Renderer::Renderer(InputVertices const& stars, unsigned numStars, unsigned tileResolution) : _dataArray(0l),
|
||||||
|
_tileArray(0l), _tiling(tileResolution) {
|
||||||
|
this->glAlloc();
|
||||||
|
|
||||||
|
Tiling tiling(tileResolution);
|
||||||
|
size_t numTiles = tiling.getTileCount();
|
||||||
|
|
||||||
|
// REVISIT: batch arrays are probably oversized, but - hey - they
|
||||||
|
// are not very large (unless for insane tiling) and we're better
|
||||||
|
// off safe than sorry
|
||||||
|
_dataArray = new GpuVertex[numStars];
|
||||||
|
_tileArray = new Tile[numTiles + 1];
|
||||||
|
_batchOffs = new GLint[numTiles * 2];
|
||||||
|
_batchCountArray = new GLsizei[numTiles * 2];
|
||||||
|
|
||||||
|
prepareVertexData(stars, numStars, tiling);
|
||||||
|
|
||||||
|
this->glUpload(numStars);
|
||||||
|
}
|
||||||
|
|
||||||
|
Renderer::~Renderer() {
|
||||||
|
delete[] _dataArray;
|
||||||
|
delete[] _tileArray;
|
||||||
|
delete[] _batchCountArray;
|
||||||
|
delete[] _batchOffs;
|
||||||
|
|
||||||
|
this->glFree();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::render(float perspective, float aspect, mat4 const& orientation, float alpha) {
|
||||||
|
float halfPersp = perspective * 0.5f;
|
||||||
|
|
||||||
|
// cancel all translation
|
||||||
|
mat4 matrix = orientation;
|
||||||
|
matrix[3][0] = 0.0f;
|
||||||
|
matrix[3][1] = 0.0f;
|
||||||
|
matrix[3][2] = 0.0f;
|
||||||
|
|
||||||
|
// extract local z vector
|
||||||
|
vec3 ahead = vec3(matrix[2]);
|
||||||
|
|
||||||
|
float azimuth = atan2(ahead.x,-ahead.z) + Radians::pi();
|
||||||
|
float altitude = atan2(-ahead.y, hypotf(ahead.x, ahead.z));
|
||||||
|
angleHorizontalPolar<Radians>(azimuth, altitude);
|
||||||
|
float const eps = 0.002f;
|
||||||
|
altitude = glm::clamp(altitude, -Radians::halfPi() + eps, Radians::halfPi() - eps);
|
||||||
|
|
||||||
|
matrix = glm::affineInverse(matrix);
|
||||||
|
|
||||||
|
this->_outIndexPos = (unsigned*) _batchOffs;
|
||||||
|
this->_wRowVec = -vec3(row(matrix, 2));
|
||||||
|
this->_halfPerspectiveAngle = halfPersp;
|
||||||
|
|
||||||
|
TileSelection::Cursor cursor;
|
||||||
|
cursor.current = _tileArray + _tiling.getTileIndex(azimuth, altitude);
|
||||||
|
cursor.firstInRow = _tileArray + _tiling.getTileIndex(0.0f, altitude);
|
||||||
|
|
||||||
|
floodFill(cursor, TileSelection(*this, _tileArray, _tileArray + _tiling.getTileCount(), (TileSelection::Cursor*) _batchCountArray));
|
||||||
|
|
||||||
|
this->glBatch(glm::value_ptr(matrix), prepareBatch((unsigned*) _batchOffs, _outIndexPos), alpha);
|
||||||
|
}
|
||||||
|
|
||||||
|
// renderer construction
|
||||||
|
|
||||||
|
void Renderer::prepareVertexData(InputVertices const& vertices, unsigned numStars, Tiling const& tiling) {
|
||||||
|
|
||||||
|
size_t nTiles = tiling.getTileCount();
|
||||||
|
size_t vertexIndex = 0u, currTileIndex = 0u, count_active = 0u;
|
||||||
|
|
||||||
|
_tileArray[0].offset = 0u;
|
||||||
|
_tileArray[0].flags = 0u;
|
||||||
|
|
||||||
|
for (InputVertices::const_iterator i = vertices.begin(), e = vertices.end(); i != e; ++i) {
|
||||||
|
size_t tileIndex = tiling.getTileIndex(i->getAzimuth(), i->getAltitude());
|
||||||
|
assert(tileIndex >= currTileIndex);
|
||||||
|
|
||||||
|
// moved on to another tile? -> flush
|
||||||
|
if (tileIndex != currTileIndex) {
|
||||||
|
|
||||||
|
Tile* tile = _tileArray + currTileIndex;
|
||||||
|
Tile* lastTile = _tileArray + tileIndex;
|
||||||
|
|
||||||
|
// set count of active vertices (upcoming lod)
|
||||||
|
tile->count = count_active;
|
||||||
|
// generate skipped, empty tiles
|
||||||
|
for(size_t offset = vertexIndex; ++tile != lastTile ;) {
|
||||||
|
tile->offset = offset, tile->count = 0u, tile->flags = 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
// initialize next (as far as possible here)
|
||||||
|
lastTile->offset = vertexIndex;
|
||||||
|
lastTile->flags = 0u;
|
||||||
|
|
||||||
|
currTileIndex = tileIndex;
|
||||||
|
count_active = 0u;
|
||||||
|
}
|
||||||
|
|
||||||
|
++count_active;
|
||||||
|
|
||||||
|
// write converted vertex
|
||||||
|
_dataArray[vertexIndex++] = *i;
|
||||||
|
}
|
||||||
|
assert(vertexIndex == numStars);
|
||||||
|
|
||||||
|
// flush last tile (see above)
|
||||||
|
Tile* tile = _tileArray + currTileIndex;
|
||||||
|
tile->count = count_active;
|
||||||
|
for (Tile* e = _tileArray + nTiles + 1; ++tile != e;) {
|
||||||
|
tile->offset = vertexIndex, tile->count = 0u, tile->flags = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Renderer::visitTile(Tile* tile) {
|
||||||
|
unsigned index = tile - _tileArray;
|
||||||
|
*_outIndexPos++ = index;
|
||||||
|
|
||||||
|
return isTileVisible(index);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Renderer::isTileVisible(unsigned index) {
|
||||||
|
|
||||||
|
float slice = _tiling.getSliceAngle();
|
||||||
|
float halfSlice = 0.5f * slice;
|
||||||
|
unsigned stride = _tiling.getAzimuthalTiles();
|
||||||
|
float azimuth = (index % stride) * slice;
|
||||||
|
float altitude = (index / stride) * slice - Radians::halfPi();
|
||||||
|
float groundX = sin(azimuth);
|
||||||
|
float groundZ = -cos(azimuth);
|
||||||
|
float elevation = cos(altitude);
|
||||||
|
vec3 tileCenter = vec3(groundX * elevation, sin(altitude), groundZ * elevation);
|
||||||
|
float w = dot(_wRowVec, tileCenter);
|
||||||
|
|
||||||
|
float daz = halfSlice * cos(std::max(0.0f, abs(altitude) - halfSlice));
|
||||||
|
float dal = halfSlice;
|
||||||
|
float adjustedNear = cos(_halfPerspectiveAngle + sqrt(daz * daz + dal * dal));
|
||||||
|
|
||||||
|
return w >= adjustedNear;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned Renderer::prepareBatch(unsigned const* indices, unsigned const* indicesEnd) {
|
||||||
|
unsigned nRanges = 0u;
|
||||||
|
GLint* offs = _batchOffs;
|
||||||
|
GLsizei* count = _batchCountArray;
|
||||||
|
|
||||||
|
for (unsigned* i = (unsigned*) _batchOffs; i != indicesEnd; ++i) {
|
||||||
|
Tile* t = _tileArray + *i;
|
||||||
|
if ((t->flags & Tile::render) > 0u && t->count > 0u) {
|
||||||
|
*offs++ = t->offset;
|
||||||
|
*count++ = t->count;
|
||||||
|
++nRanges;
|
||||||
|
}
|
||||||
|
t->flags = 0;
|
||||||
|
}
|
||||||
|
return nRanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
// GL API handling
|
||||||
|
|
||||||
|
void Renderer::glAlloc() {
|
||||||
|
GLchar const* const VERTEX_SHADER =
|
||||||
|
"#version 120\n"
|
||||||
|
"uniform float alpha;\n"
|
||||||
|
"void main(void) {\n"
|
||||||
|
" vec3 c = gl_Color.rgb * 1.22;\n"
|
||||||
|
" float s = min(max(tan((c.r + c.g + c.b) / 3), 1.0), 3.0);\n"
|
||||||
|
" gl_Position = ftransform();\n"
|
||||||
|
" gl_FrontColor= gl_Color * alpha * 1.5;\n"
|
||||||
|
" gl_PointSize = s;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
_program.addShaderFromSourceCode(QGLShader::Vertex, VERTEX_SHADER);
|
||||||
|
|
||||||
|
GLchar const* const FRAGMENT_SHADER =
|
||||||
|
"#version 120\n"
|
||||||
|
"void main(void) {\n"
|
||||||
|
" gl_FragColor = gl_Color;\n"
|
||||||
|
"}\n";
|
||||||
|
|
||||||
|
_program.addShaderFromSourceCode(QGLShader::Fragment, FRAGMENT_SHADER);
|
||||||
|
_program.link();
|
||||||
|
_alphaLocationHandle = _program.uniformLocation("alpha");
|
||||||
|
|
||||||
|
glGenBuffersARB(1, & _vertexArrayHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::glFree() {
|
||||||
|
glDeleteBuffersARB(1, & _vertexArrayHandle);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::glUpload(GLsizei numStars) {
|
||||||
|
glBindBufferARB(GL_ARRAY_BUFFER, _vertexArrayHandle);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, numStars * sizeof(GpuVertex), _dataArray, GL_STATIC_DRAW);
|
||||||
|
glBindBufferARB(GL_ARRAY_BUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::glBatch(GLfloat const* matrix, GLsizei n_ranges, float alpha) {
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glDisable(GL_LIGHTING);
|
||||||
|
|
||||||
|
// setup modelview matrix
|
||||||
|
glPushMatrix();
|
||||||
|
glLoadMatrixf(matrix);
|
||||||
|
|
||||||
|
// set point size and smoothing + shader control
|
||||||
|
glPointSize(1.0f);
|
||||||
|
glEnable(GL_POINT_SMOOTH);
|
||||||
|
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
|
||||||
|
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||||
|
|
||||||
|
// select shader and vertex array
|
||||||
|
_program.bind();
|
||||||
|
_program.setUniformValue(_alphaLocationHandle, alpha);
|
||||||
|
glBindBufferARB(GL_ARRAY_BUFFER, _vertexArrayHandle);
|
||||||
|
glInterleavedArrays(GL_C4UB_V3F, sizeof(GpuVertex), 0l);
|
||||||
|
|
||||||
|
// render
|
||||||
|
glMultiDrawArrays(GL_POINTS, _batchOffs, _batchCountArray, n_ranges);
|
||||||
|
|
||||||
|
// restore state
|
||||||
|
glBindBufferARB(GL_ARRAY_BUFFER, 0);
|
||||||
|
_program.release();
|
||||||
|
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
||||||
|
glDisable(GL_POINT_SMOOTH);
|
||||||
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
|
||||||
|
glPopMatrix();
|
||||||
|
}
|
||||||
|
|
||||||
|
// flood fill strategy
|
||||||
|
|
||||||
|
bool Renderer::TileSelection::select(Renderer::TileSelection::Cursor const& cursor) {
|
||||||
|
Tile* tile = cursor.current;
|
||||||
|
|
||||||
|
if (tile < _tileArray || tile >= _tilesEnd || !! (tile->flags & Tile::checked)) {
|
||||||
|
// out of bounds or been here already
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// will check now and never again
|
||||||
|
tile->flags |= Tile::checked;
|
||||||
|
if (_rendererRef.visitTile(tile)) {
|
||||||
|
// good one -> remember (for batching) and propagate
|
||||||
|
tile->flags |= Tile::render;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Renderer::TileSelection::process(Renderer::TileSelection::Cursor const& cursor) {
|
||||||
|
Tile* tile = cursor.current;
|
||||||
|
|
||||||
|
if (! (tile->flags & Tile::visited)) {
|
||||||
|
tile->flags |= Tile::visited;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::TileSelection::right(Renderer::TileSelection::Cursor& cursor) const {
|
||||||
|
cursor.current += 1;
|
||||||
|
if (cursor.current == cursor.firstInRow + _rendererRef._tiling.getAzimuthalTiles()) {
|
||||||
|
cursor.current = cursor.firstInRow;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::TileSelection::left(Renderer::TileSelection::Cursor& cursor) const {
|
||||||
|
if (cursor.current == cursor.firstInRow) {
|
||||||
|
cursor.current = cursor.firstInRow + _rendererRef._tiling.getAzimuthalTiles();
|
||||||
|
}
|
||||||
|
cursor.current -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::TileSelection::up(Renderer::TileSelection::Cursor& cursor) const {
|
||||||
|
unsigned numTiles = _rendererRef._tiling.getAzimuthalTiles();
|
||||||
|
cursor.current += numTiles;
|
||||||
|
cursor.firstInRow += numTiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::TileSelection::down(Renderer::TileSelection::Cursor& cursor) const {
|
||||||
|
unsigned numTiles = _rendererRef._tiling.getAzimuthalTiles();
|
||||||
|
cursor.current -= numTiles;
|
||||||
|
cursor.firstInRow -= numTiles;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Renderer::TileSelection::defer(Renderer::TileSelection::Cursor const& cursor) {
|
||||||
|
*_stackPos++ = cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Renderer::TileSelection::deferred(Renderer::TileSelection::Cursor& cursor) {
|
||||||
|
if (_stackPos != _stackArray) {
|
||||||
|
cursor = *--_stackPos;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
506
interface/src/starfield/renderer/Renderer.h
Normal file → Executable file
506
interface/src/starfield/renderer/Renderer.h
Normal file → Executable file
|
@ -3,24 +3,18 @@
|
||||||
// interface
|
// interface
|
||||||
//
|
//
|
||||||
// Created by Tobias Schwinger on 3/22/13.
|
// Created by Tobias Schwinger on 3/22/13.
|
||||||
|
// Modified 10/17/13 Chris Barnard.
|
||||||
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
//
|
//
|
||||||
|
|
||||||
#ifndef __interface__starfield__renderer__Renderer__
|
#ifndef __interface__starfield__renderer__Renderer__
|
||||||
#define __interface__starfield__renderer__Renderer__
|
#define __interface__starfield__renderer__Renderer__
|
||||||
|
|
||||||
#ifndef __interface__Starfield_impl__
|
|
||||||
#error "This is an implementation file - not intended for direct inclusion."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#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/Tile.h"
|
#include "starfield/data/Tile.h"
|
||||||
#include "starfield/data/GpuVertex.h"
|
#include "starfield/data/GpuVertex.h"
|
||||||
|
#include "starfield/renderer/Tiling.h"
|
||||||
#include "Tiling.h"
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// FOV culling
|
// FOV culling
|
||||||
|
@ -66,174 +60,14 @@ namespace starfield {
|
||||||
class Renderer {
|
class Renderer {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Renderer(InputVertices const& src,
|
Renderer(InputVertices const& src, unsigned numStars, unsigned tileResolution);
|
||||||
size_t n,
|
~Renderer();
|
||||||
unsigned k,
|
void render(float perspective, float aspect, mat4 const& orientation, float alpha);
|
||||||
BrightnessLevel b,
|
|
||||||
BrightnessLevel bMin) :
|
|
||||||
|
|
||||||
_dataArray(0l),
|
|
||||||
_tileArray(0l),
|
|
||||||
_tiling(k) {
|
|
||||||
|
|
||||||
this->glAlloc();
|
|
||||||
|
|
||||||
Tiling tiling(k);
|
|
||||||
size_t nTiles = tiling.getTileCount();
|
|
||||||
|
|
||||||
// REVISIT: could coalesce allocation for faster rebuild
|
|
||||||
// REVISIT: batch arrays are probably oversized, but - hey - they
|
|
||||||
// are not very large (unless for insane tiling) and we're better
|
|
||||||
// off safe than sorry
|
|
||||||
_dataArray = new GpuVertex[n];
|
|
||||||
_tileArray = new Tile[nTiles + 1];
|
|
||||||
_batchOffs = new GLint[nTiles * 2];
|
|
||||||
_batchCountArray = new GLsizei[nTiles * 2];
|
|
||||||
|
|
||||||
prepareVertexData(src, n, tiling, b, bMin);
|
|
||||||
|
|
||||||
this->glUpload(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
~Renderer() {
|
|
||||||
|
|
||||||
delete[] _dataArray;
|
|
||||||
delete[] _tileArray;
|
|
||||||
delete[] _batchCountArray;
|
|
||||||
delete[] _batchOffs;
|
|
||||||
|
|
||||||
this->glFree();
|
|
||||||
}
|
|
||||||
|
|
||||||
void render(float perspective,
|
|
||||||
float aspect,
|
|
||||||
mat4 const& orientation,
|
|
||||||
BrightnessLevel minBright,
|
|
||||||
float alpha) {
|
|
||||||
|
|
||||||
// printLog("
|
|
||||||
// Stars.cpp: rendering at minimal brightness %d\n", minBright);
|
|
||||||
|
|
||||||
float halfPersp = perspective * 0.5f;
|
|
||||||
|
|
||||||
// cancel all translation
|
|
||||||
mat4 matrix = orientation;
|
|
||||||
matrix[3][0] = 0.0f;
|
|
||||||
matrix[3][1] = 0.0f;
|
|
||||||
matrix[3][2] = 0.0f;
|
|
||||||
|
|
||||||
// extract local z vector
|
|
||||||
vec3 ahead = vec3(matrix[2]);
|
|
||||||
|
|
||||||
float azimuth = atan2(ahead.x,-ahead.z) + Radians::pi();
|
|
||||||
float altitude = atan2(-ahead.y, hypotf(ahead.x, ahead.z));
|
|
||||||
angleHorizontalPolar<Radians>(azimuth, altitude);
|
|
||||||
float const eps = 0.002f;
|
|
||||||
altitude = glm::clamp(altitude,
|
|
||||||
-Radians::halfPi() + eps, Radians::halfPi() - eps);
|
|
||||||
#if STARFIELD_HEMISPHERE_ONLY
|
|
||||||
altitude = std::max(0.0f, altitude);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if STARFIELD_DEBUG_CULLING
|
|
||||||
mat4 matrix_debug = glm::translate(vec3(0.0f, 0.0f, -4.0f)) *
|
|
||||||
glm::affineInverse(matrix);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
matrix = glm::affineInverse(matrix);
|
|
||||||
|
|
||||||
this->_outIndexPos = (unsigned*) _batchOffs;
|
|
||||||
this->_wRowVec = -vec3(row(matrix, 2));
|
|
||||||
this->_halfPerspectiveAngle = halfPersp;
|
|
||||||
this->_minBright = minBright;
|
|
||||||
|
|
||||||
TileSelection::Cursor cursor;
|
|
||||||
cursor.current = _tileArray + _tiling.getTileIndex(azimuth, altitude);
|
|
||||||
cursor.firstInRow = _tileArray + _tiling.getTileIndex(0.0f, altitude);
|
|
||||||
|
|
||||||
floodFill(cursor, TileSelection(*this, _tileArray, _tileArray + _tiling.getTileCount(),
|
|
||||||
(TileSelection::Cursor*) _batchCountArray));
|
|
||||||
|
|
||||||
#if STARFIELD_DEBUG_CULLING
|
|
||||||
# define matrix matrix_debug
|
|
||||||
#endif
|
|
||||||
this->glBatch(glm::value_ptr(matrix), prepareBatch(
|
|
||||||
(unsigned*) _batchOffs, _outIndexPos), alpha);
|
|
||||||
|
|
||||||
#if STARFIELD_DEBUG_CULLING
|
|
||||||
# undef matrix
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// renderer construction
|
// renderer construction
|
||||||
|
|
||||||
void prepareVertexData(InputVertices const& src,
|
void prepareVertexData(InputVertices const& vertices, unsigned numStars, Tiling const& tiling);
|
||||||
size_t n, // <-- at bMin and brighter
|
|
||||||
Tiling const& tiling,
|
|
||||||
BrightnessLevel b,
|
|
||||||
BrightnessLevel bMin) {
|
|
||||||
|
|
||||||
size_t nTiles = tiling.getTileCount();
|
|
||||||
size_t vertexIndex = 0u, currTileIndex = 0u, count_active = 0u;
|
|
||||||
|
|
||||||
_tileArray[0].offset = 0u;
|
|
||||||
_tileArray[0].lod = b;
|
|
||||||
_tileArray[0].flags = 0u;
|
|
||||||
|
|
||||||
for (InputVertices::const_iterator i =
|
|
||||||
src.begin(), e = src.end(); i != e; ++i) {
|
|
||||||
|
|
||||||
BrightnessLevel bv = getBrightness(i->getColor());
|
|
||||||
// filter by alloc brightness
|
|
||||||
if (bv >= bMin) {
|
|
||||||
|
|
||||||
size_t tileIndex = tiling.getTileIndex(
|
|
||||||
i->getAzimuth(), i->getAltitude());
|
|
||||||
|
|
||||||
assert(tileIndex >= currTileIndex);
|
|
||||||
|
|
||||||
// moved on to another tile? -> flush
|
|
||||||
if (tileIndex != currTileIndex) {
|
|
||||||
|
|
||||||
Tile* t = _tileArray + currTileIndex;
|
|
||||||
Tile* tLast = _tileArray + tileIndex;
|
|
||||||
|
|
||||||
// set count of active vertices (upcoming lod)
|
|
||||||
t->count = count_active;
|
|
||||||
// generate skipped, empty tiles
|
|
||||||
for(size_t offs = vertexIndex; ++t != tLast ;) {
|
|
||||||
t->offset = offs, t->count = 0u,
|
|
||||||
t->lod = b, t->flags = 0u;
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize next (as far as possible here)
|
|
||||||
tLast->offset = vertexIndex;
|
|
||||||
tLast->lod = b;
|
|
||||||
tLast->flags = 0u;
|
|
||||||
|
|
||||||
currTileIndex = tileIndex;
|
|
||||||
count_active = 0u;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (bv >= b)
|
|
||||||
++count_active;
|
|
||||||
|
|
||||||
// printLog("Stars.cpp: Vertex %d on tile #%d\n", vertexIndex, tileIndex);
|
|
||||||
|
|
||||||
// write converted vertex
|
|
||||||
_dataArray[vertexIndex++] = *i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
assert(vertexIndex == n);
|
|
||||||
// flush last tile (see above)
|
|
||||||
Tile* t = _tileArray + currTileIndex;
|
|
||||||
t->count = count_active;
|
|
||||||
for (Tile* e = _tileArray + nTiles + 1; ++t != e;) {
|
|
||||||
t->offset = vertexIndex, t->count = 0u,
|
|
||||||
t->lod = b, t->flags = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// FOV culling / LOD
|
// FOV culling / LOD
|
||||||
|
|
||||||
|
@ -242,299 +76,65 @@ namespace starfield {
|
||||||
|
|
||||||
class TileSelection {
|
class TileSelection {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
struct Cursor { Tile* current, * firstInRow; };
|
struct Cursor { Tile* current, * firstInRow; };
|
||||||
private:
|
|
||||||
Renderer& _rendererRef;
|
private:
|
||||||
Cursor* const _stackArray;
|
Renderer& _rendererRef;
|
||||||
Cursor* _stackPos;
|
Cursor* const _stackArray;
|
||||||
Tile const* const _tileArray;
|
Cursor* _stackPos;
|
||||||
Tile const* const _tilesEnd;
|
Tile const* const _tileArray;
|
||||||
|
Tile const* const _tilesEnd;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
TileSelection(Renderer& renderer, Tile const* tiles, Tile const* tiles_end, Cursor* stack) :
|
||||||
TileSelection(Renderer& renderer, Tile const* tiles,
|
_rendererRef(renderer),
|
||||||
Tile const* tiles_end, Cursor* stack) :
|
_stackArray(stack),
|
||||||
|
_stackPos(stack),
|
||||||
_rendererRef(renderer),
|
_tileArray(tiles),
|
||||||
_stackArray(stack),
|
_tilesEnd(tiles_end) { }
|
||||||
_stackPos(stack),
|
|
||||||
_tileArray(tiles),
|
|
||||||
_tilesEnd(tiles_end) {
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
bool select(Cursor const& cursor);
|
||||||
// flood fill strategy
|
bool process(Cursor const& cursor);
|
||||||
|
void right(Cursor& cursor) const;
|
||||||
bool select(Cursor const& c) {
|
void left(Cursor& cursor) const;
|
||||||
Tile* t = c.current;
|
void up(Cursor& cursor) const;
|
||||||
|
void down(Cursor& cursor) const;
|
||||||
if (t < _tileArray || t >= _tilesEnd ||
|
void defer(Cursor const& cursor);
|
||||||
!! (t->flags & Tile::checked)) {
|
bool deferred(Cursor& cursor);
|
||||||
|
|
||||||
// out of bounds or been here already
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// will check now and never again
|
|
||||||
t->flags |= Tile::checked;
|
|
||||||
if (_rendererRef.visitTile(t)) {
|
|
||||||
|
|
||||||
// good one -> remember (for batching) and propagate
|
|
||||||
t->flags |= Tile::render;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool process(Cursor const& c) {
|
|
||||||
Tile* t = c.current;
|
|
||||||
|
|
||||||
if (! (t->flags & Tile::visited)) {
|
|
||||||
|
|
||||||
t->flags |= Tile::visited;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void right(Cursor& c) const {
|
|
||||||
|
|
||||||
c.current += 1;
|
|
||||||
if (c.current == c.firstInRow + _rendererRef._tiling.getAzimuthalTiles()) {
|
|
||||||
c.current = c.firstInRow;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void left(Cursor& c) const {
|
|
||||||
|
|
||||||
if (c.current == c.firstInRow) {
|
|
||||||
c.current = c.firstInRow + _rendererRef._tiling.getAzimuthalTiles();
|
|
||||||
}
|
|
||||||
c.current -= 1;
|
|
||||||
}
|
|
||||||
void up(Cursor& c) const {
|
|
||||||
|
|
||||||
unsigned d = _rendererRef._tiling.getAzimuthalTiles();
|
|
||||||
c.current += d;
|
|
||||||
c.firstInRow += d;
|
|
||||||
}
|
|
||||||
void down(Cursor& c) const {
|
|
||||||
|
|
||||||
unsigned d = _rendererRef._tiling.getAzimuthalTiles();
|
|
||||||
c.current -= d;
|
|
||||||
c.firstInRow -= d;
|
|
||||||
}
|
|
||||||
|
|
||||||
void defer(Cursor const& t) {
|
|
||||||
|
|
||||||
*_stackPos++ = t;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool deferred(Cursor& cursor) {
|
|
||||||
|
|
||||||
if (_stackPos != _stackArray) {
|
|
||||||
cursor = *--_stackPos;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
bool visitTile(Tile* t) {
|
bool visitTile(Tile* tile);
|
||||||
|
bool isTileVisible(unsigned index);
|
||||||
unsigned index = t - _tileArray;
|
unsigned prepareBatch(unsigned const* indices, unsigned const* indicesEnd);
|
||||||
*_outIndexPos++ = index;
|
|
||||||
|
|
||||||
if (! tileVisible(t, index)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (t->lod != _minBright) {
|
|
||||||
updateVertexCount(t, _minBright);
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool tileVisible(Tile* t, unsigned i) {
|
|
||||||
|
|
||||||
float slice = _tiling.getSliceAngle();
|
|
||||||
float halfSlice = 0.5f * slice;
|
|
||||||
unsigned stride = _tiling.getAzimuthalTiles();
|
|
||||||
float azimuth = (i % stride) * slice;
|
|
||||||
float altitude = (i / stride) * slice - Radians::halfPi();
|
|
||||||
float gx = sin(azimuth);
|
|
||||||
float gz = -cos(azimuth);
|
|
||||||
float exz = cos(altitude);
|
|
||||||
vec3 tileCenter = vec3(gx * exz, sin(altitude), gz * exz);
|
|
||||||
float w = dot(_wRowVec, tileCenter);
|
|
||||||
|
|
||||||
float daz = halfSlice * cos(std::max(0.0f, abs(altitude) - halfSlice));
|
|
||||||
float dal = halfSlice;
|
|
||||||
float adjustedNear = cos(_halfPerspectiveAngle + sqrt(daz * daz + dal * dal));
|
|
||||||
|
|
||||||
// printLog("Stars.cpp: checking tile #%d, w = %f, near = %f\n", i, w, nearClip);
|
|
||||||
|
|
||||||
return w >= adjustedNear;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateVertexCount(Tile* t, BrightnessLevel minBright) {
|
|
||||||
|
|
||||||
// a growing number of stars needs to be rendereed when the
|
|
||||||
// minimum brightness decreases
|
|
||||||
// perform a binary search in the so found partition for the
|
|
||||||
// new vertex count of this tile
|
|
||||||
|
|
||||||
GpuVertex const* start = _dataArray + t[0].offset;
|
|
||||||
GpuVertex const* end = _dataArray + t[1].offset;
|
|
||||||
|
|
||||||
assert(end >= start);
|
|
||||||
|
|
||||||
if (start == end)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (t->lod < minBright)
|
|
||||||
end = start + t->count;
|
|
||||||
else
|
|
||||||
start += (t->count > 0 ? t->count - 1 : 0);
|
|
||||||
|
|
||||||
end = std::upper_bound(
|
|
||||||
start, end, minBright, GreaterBrightness());
|
|
||||||
|
|
||||||
assert(end >= _dataArray + t[0].offset);
|
|
||||||
|
|
||||||
t->count = end - _dataArray - t[0].offset;
|
|
||||||
t->lod = minBright;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned prepareBatch(unsigned const* indices,
|
|
||||||
unsigned const* indicesEnd) {
|
|
||||||
|
|
||||||
unsigned nRanges = 0u;
|
|
||||||
GLint* offs = _batchOffs;
|
|
||||||
GLsizei* count = _batchCountArray;
|
|
||||||
|
|
||||||
for (unsigned* i = (unsigned*) _batchOffs;
|
|
||||||
i != indicesEnd; ++i) {
|
|
||||||
|
|
||||||
Tile* t = _tileArray + *i;
|
|
||||||
if ((t->flags & Tile::render) > 0u && t->count > 0u) {
|
|
||||||
|
|
||||||
*offs++ = t->offset;
|
|
||||||
*count++ = t->count;
|
|
||||||
++nRanges;
|
|
||||||
}
|
|
||||||
t->flags = 0;
|
|
||||||
}
|
|
||||||
return nRanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
// GL API handling
|
// GL API handling
|
||||||
|
|
||||||
void glAlloc() {
|
void glAlloc();
|
||||||
|
void glFree();
|
||||||
GLchar const* const VERTEX_SHADER =
|
void glUpload(GLsizei numStars);
|
||||||
"#version 120\n"
|
void glBatch(GLfloat const* matrix, GLsizei n_ranges, float alpha);
|
||||||
"uniform float alpha;\n"
|
|
||||||
"void main(void) {\n"
|
|
||||||
|
|
||||||
" vec3 c = gl_Color.rgb * 1.0125;\n"
|
|
||||||
" float s = max(1.0, dot(c, c) * 0.7);\n"
|
|
||||||
|
|
||||||
" gl_Position = ftransform();\n"
|
|
||||||
" gl_FrontColor= gl_Color * alpha;\n"
|
|
||||||
" gl_PointSize = s;\n"
|
|
||||||
"}\n";
|
|
||||||
|
|
||||||
_program.addShaderFromSourceCode(QGLShader::Vertex, VERTEX_SHADER);
|
|
||||||
GLchar const* const FRAGMENT_SHADER =
|
|
||||||
"#version 120\n"
|
|
||||||
"void main(void) {\n"
|
|
||||||
" gl_FragColor = gl_Color;\n"
|
|
||||||
"}\n";
|
|
||||||
_program.addShaderFromSourceCode(QGLShader::Fragment, FRAGMENT_SHADER);
|
|
||||||
_program.link();
|
|
||||||
_alphaLocationHandle = _program.uniformLocation("alpha");
|
|
||||||
|
|
||||||
glGenBuffersARB(1, & _vertexArrayHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void glFree() {
|
|
||||||
|
|
||||||
glDeleteBuffersARB(1, & _vertexArrayHandle);
|
|
||||||
}
|
|
||||||
|
|
||||||
void glUpload(GLsizei n) {
|
|
||||||
glBindBufferARB(GL_ARRAY_BUFFER, _vertexArrayHandle);
|
|
||||||
glBufferData(GL_ARRAY_BUFFER,
|
|
||||||
n * sizeof(GpuVertex), _dataArray, GL_STATIC_DRAW);
|
|
||||||
//glInterleavedArrays(GL_C4UB_V3F, sizeof(GpuVertex), 0l);
|
|
||||||
|
|
||||||
glBindBufferARB(GL_ARRAY_BUFFER, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void glBatch(GLfloat const* matrix, GLsizei n_ranges, float alpha) {
|
|
||||||
|
|
||||||
// printLog("Stars.cpp: rendering %d-multibatch\n", n_ranges);
|
|
||||||
|
|
||||||
// for (int i = 0; i < n_ranges; ++i)
|
|
||||||
// printLog("Stars.cpp: Batch #%d - %d stars @ %d\n", i,
|
|
||||||
// _batchOffs[i], _batchCountArray[i]);
|
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
|
||||||
glDisable(GL_LIGHTING);
|
|
||||||
|
|
||||||
// setup modelview matrix
|
|
||||||
glPushMatrix();
|
|
||||||
glLoadMatrixf(matrix);
|
|
||||||
|
|
||||||
// set point size and smoothing + shader control
|
|
||||||
glPointSize(1.0f);
|
|
||||||
glEnable(GL_POINT_SMOOTH);
|
|
||||||
glHint(GL_POINT_SMOOTH_HINT, GL_NICEST);
|
|
||||||
glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
|
||||||
|
|
||||||
// select shader and vertex array
|
|
||||||
_program.bind();
|
|
||||||
_program.setUniformValue(_alphaLocationHandle, alpha);
|
|
||||||
glBindBufferARB(GL_ARRAY_BUFFER, _vertexArrayHandle);
|
|
||||||
glInterleavedArrays(GL_C4UB_V3F, sizeof(GpuVertex), 0l);
|
|
||||||
|
|
||||||
// render
|
|
||||||
glMultiDrawArrays(GL_POINTS,
|
|
||||||
_batchOffs, _batchCountArray, n_ranges);
|
|
||||||
|
|
||||||
// restore state
|
|
||||||
glBindBufferARB(GL_ARRAY_BUFFER, 0);
|
|
||||||
_program.release();
|
|
||||||
glDisable(GL_VERTEX_PROGRAM_POINT_SIZE);
|
|
||||||
glDisable(GL_POINT_SMOOTH);
|
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
|
||||||
|
|
||||||
glPopMatrix();
|
|
||||||
}
|
|
||||||
|
|
||||||
// variables
|
// variables
|
||||||
|
|
||||||
GpuVertex* _dataArray;
|
GpuVertex* _dataArray;
|
||||||
Tile* _tileArray;
|
Tile* _tileArray;
|
||||||
GLint* _batchOffs;
|
GLint* _batchOffs;
|
||||||
GLsizei* _batchCountArray;
|
GLsizei* _batchCountArray;
|
||||||
GLuint _vertexArrayHandle;
|
GLuint _vertexArrayHandle;
|
||||||
ProgramObject _program;
|
ProgramObject _program;
|
||||||
int _alphaLocationHandle;
|
int _alphaLocationHandle;
|
||||||
|
|
||||||
Tiling _tiling;
|
Tiling _tiling;
|
||||||
|
|
||||||
unsigned* _outIndexPos;
|
unsigned* _outIndexPos;
|
||||||
vec3 _wRowVec;
|
vec3 _wRowVec;
|
||||||
float _halfPerspectiveAngle;
|
float _halfPerspectiveAngle;
|
||||||
BrightnessLevel _minBright;
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
61
interface/src/starfield/renderer/Tiling.h
Normal file → Executable file
61
interface/src/starfield/renderer/Tiling.h
Normal file → Executable file
|
@ -9,10 +9,6 @@
|
||||||
#ifndef __interface__starfield__renderer__Tiling__
|
#ifndef __interface__starfield__renderer__Tiling__
|
||||||
#define __interface__starfield__renderer__Tiling__
|
#define __interface__starfield__renderer__Tiling__
|
||||||
|
|
||||||
#ifndef __interface__Starfield_impl__
|
|
||||||
#error "This is an implementation file - not intended for direct inclusion."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "starfield/Config.h"
|
#include "starfield/Config.h"
|
||||||
|
|
||||||
namespace starfield {
|
namespace starfield {
|
||||||
|
@ -20,53 +16,34 @@ namespace starfield {
|
||||||
class Tiling {
|
class Tiling {
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Tiling(unsigned k) :
|
Tiling(unsigned tileResolution) : _tileResolution(tileResolution), _rcpSlice(tileResolution / Radians::twicePi()) {
|
||||||
_valK(k),
|
_nBits = ceil(log(getTileCount()) * LOG2); }
|
||||||
_rcpSlice(k / Radians::twicePi()) {
|
|
||||||
_nBits = ceil(log(getTileCount()) * 1.4426950408889634); // log2
|
unsigned getAzimuthalTiles() const { return _tileResolution; }
|
||||||
}
|
unsigned getAltitudinalTiles() const { return _tileResolution / 2 + 1; }
|
||||||
|
|
||||||
unsigned getAzimuthalTiles() const { return _valK; }
|
|
||||||
unsigned getAltitudinalTiles() const { return _valK / 2 + 1; }
|
|
||||||
unsigned getTileIndexBits() const { return _nBits; }
|
unsigned getTileIndexBits() const { return _nBits; }
|
||||||
|
unsigned getTileCount() const { return getAzimuthalTiles() * getAltitudinalTiles(); }
|
||||||
unsigned getTileCount() const {
|
unsigned getTileIndex(float azimuth, float altitude) const { return discreteAzimuth(azimuth) +
|
||||||
return getAzimuthalTiles() * getAltitudinalTiles();
|
_tileResolution * discreteAltitude(altitude); }
|
||||||
}
|
float getSliceAngle() const { return 1.0f / _rcpSlice; }
|
||||||
|
|
||||||
unsigned getTileIndex(float azimuth, float altitude) const {
|
|
||||||
return discreteAzimuth(azimuth) +
|
|
||||||
_valK * discreteAltitude(altitude);
|
|
||||||
}
|
|
||||||
|
|
||||||
float getSliceAngle() const {
|
|
||||||
return 1.0f / _rcpSlice;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
unsigned discreteAngle(float unsigned_angle) const {
|
unsigned discreteAngle(float unsigned_angle) const { return unsigned(floor(unsigned_angle * _rcpSlice + 0.5f)); }
|
||||||
|
unsigned discreteAzimuth(float angle) const { return discreteAngle(angle) % _tileResolution; }
|
||||||
return unsigned(floor(unsigned_angle * _rcpSlice + 0.5f));
|
unsigned discreteAltitude(float angle) const { return min( getAltitudinalTiles() - 1,
|
||||||
}
|
discreteAngle(angle + Radians::halfPi()) ); }
|
||||||
|
|
||||||
unsigned discreteAzimuth(float a) const {
|
|
||||||
return discreteAngle(a) % _valK;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned discreteAltitude(float a) const {
|
|
||||||
return min(getAltitudinalTiles() - 1,
|
|
||||||
discreteAngle(a + Radians::halfPi()) );
|
|
||||||
}
|
|
||||||
|
|
||||||
// variables
|
// variables
|
||||||
|
|
||||||
unsigned _valK;
|
unsigned _tileResolution;
|
||||||
float _rcpSlice;
|
float _rcpSlice;
|
||||||
unsigned _nBits;
|
unsigned _nBits;
|
||||||
|
|
||||||
|
const float LOG2 = 1.4426950408889634;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // anonymous namespace
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
18
interface/src/starfield/renderer/VertexOrder.cpp
Executable file
18
interface/src/starfield/renderer/VertexOrder.cpp
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
//
|
||||||
|
// starfield/renderer/VertexOrder.cpp
|
||||||
|
// interface
|
||||||
|
//
|
||||||
|
// Created by Chris Barnard on 10/17/13.
|
||||||
|
// Based on code by Tobias Schwinger on 3/22/13.
|
||||||
|
//
|
||||||
|
// Copyright (c) 2013 High Fidelity, Inc. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "starfield/renderer/VertexOrder.h"
|
||||||
|
|
||||||
|
using namespace starfield;
|
||||||
|
|
||||||
|
bool VertexOrder::bit(InputVertex const& vertex, state_type const& state) const {
|
||||||
|
unsigned key = _tiling.getTileIndex(vertex.getAzimuth(), vertex.getAltitude());
|
||||||
|
return base::bit(key, state);
|
||||||
|
}
|
24
interface/src/starfield/renderer/VertexOrder.h
Normal file → Executable file
24
interface/src/starfield/renderer/VertexOrder.h
Normal file → Executable file
|
@ -9,37 +9,23 @@
|
||||||
#ifndef __interface__starfield__renderer__VertexOrder__
|
#ifndef __interface__starfield__renderer__VertexOrder__
|
||||||
#define __interface__starfield__renderer__VertexOrder__
|
#define __interface__starfield__renderer__VertexOrder__
|
||||||
|
|
||||||
#ifndef __interface__Starfield_impl__
|
|
||||||
#error "This is an implementation file - not intended for direct inclusion."
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "starfield/Config.h"
|
#include "starfield/Config.h"
|
||||||
#include "starfield/data/InputVertex.h"
|
#include "starfield/data/InputVertex.h"
|
||||||
#include "starfield/renderer/Tiling.h"
|
#include "starfield/renderer/Tiling.h"
|
||||||
|
|
||||||
namespace starfield {
|
namespace starfield {
|
||||||
|
|
||||||
/**
|
// Defines the vertex order for the renderer as a bit extractor for
|
||||||
* Defines the vertex order for the renderer as a bit extractor for
|
//binary in-place Radix Sort.
|
||||||
* binary in-place Radix Sort.
|
|
||||||
*/
|
|
||||||
class VertexOrder : public Radix2IntegerScanner<unsigned>
|
class VertexOrder : public Radix2IntegerScanner<unsigned>
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit VertexOrder(Tiling const& tiling) :
|
explicit VertexOrder(Tiling const& tiling) :
|
||||||
|
|
||||||
base(tiling.getTileIndexBits() + BrightnessBits),
|
base(tiling.getTileIndexBits()), _tiling(tiling) { }
|
||||||
_tiling(tiling) {
|
|
||||||
}
|
|
||||||
|
|
||||||
bool bit(InputVertex const& v, state_type const& s) const {
|
bool bit(InputVertex const& vertex, state_type const& state) const;
|
||||||
|
|
||||||
// inspect (tile_index, brightness) tuples
|
|
||||||
unsigned key = getBrightness(v.getColor()) ^ BrightnessMask;
|
|
||||||
key |= _tiling.getTileIndex(
|
|
||||||
v.getAzimuth(), v.getAltitude()) << BrightnessBits;
|
|
||||||
return base::bit(key, s);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Tiling _tiling;
|
Tiling _tiling;
|
||||||
|
|
Loading…
Reference in a new issue