diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 8f08b75a93..7c7ab7aab6 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -72,8 +72,8 @@ using namespace std; // Starfield information -static char STAR_FILE[] = "http://s3-us-west-1.amazonaws.com/highfidelity/stars.txt"; -static char STAR_CACHE_FILE[] = "cachedStars.txt"; +static unsigned STARFIELD_NUM_STARS = 50000; +static unsigned STARFIELD_SEED = 1; 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)) { PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "Application::displaySide() ... stars..."); - if (!_stars.getFileLoaded()) { - _stars.readInput(STAR_FILE, STAR_CACHE_FILE, 0); + if (!_stars.isStarsLoaded()) { + _stars.generate(STARFIELD_NUM_STARS, STARFIELD_SEED); } // should be the first rendering pass - w/o depth buffer / lighting diff --git a/interface/src/Stars.cpp b/interface/src/Stars.cpp old mode 100644 new mode 100755 index e663ef33bd..15beff5e9d --- a/interface/src/Stars.cpp +++ b/interface/src/Stars.cpp @@ -14,27 +14,23 @@ #undef __interface__Starfield_impl__ Stars::Stars() : - _controller(0l), _fileLoaded(false) { - _controller = new starfield::Controller; + _controller(0l), _starsLoaded(false) { + _controller = new starfield::Controller; } Stars::~Stars() { delete _controller; } -bool Stars::readInput(const char* url, const char* cacheFile, unsigned limit) { - _fileLoaded = _controller->readInput(url, cacheFile, limit); - return _fileLoaded; +bool Stars::generate(unsigned numStars, unsigned seed) { + _starsLoaded = _controller->computeStars(numStars, seed); + return _starsLoaded; } bool Stars::setResolution(unsigned 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) { // determine length of screen diagonal from quadrant height and aspect ratio diff --git a/interface/src/Stars.h b/interface/src/Stars.h old mode 100644 new mode 100755 index 83d55d3766..99d5149f37 --- a/interface/src/Stars.h +++ b/interface/src/Stars.h @@ -21,13 +21,12 @@ class Stars { Stars(); ~Stars(); - // - // Reads input file from URL. Returns true upon success. // - // The limit parameter allows to reduce the number of stars - // that are loaded, keeping the brightest ones. - // - bool readInput(const char* url, const char* cacheFile = 0l, unsigned limit = 200000); + // Generate stars from random number seed + // + // The numStars parameter sets the number of stars to generate. + // + bool generate(unsigned numStars, unsigned seed); // // Renders the starfield from a local viewer's perspective. @@ -45,27 +44,12 @@ class Stars { // is returned. // 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 - // 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'. + // Returns true when stars have been loaded // - // The current level of detail is returned as a float in [0;1]. - // - float changeLOD(float factor, - float overalloc = 0.25, float realloc = 0.15); - - bool getFileLoaded() const { return _fileLoaded; }; + bool isStarsLoaded() const { return _starsLoaded; }; private: // don't copy/assign Stars(Stars const&); // = delete; @@ -75,7 +59,7 @@ class Stars { starfield::Controller* _controller; - bool _fileLoaded; + bool _starsLoaded; }; diff --git a/interface/src/starfield/CMakeLists.txt b/interface/src/starfield/CMakeLists.txt old mode 100644 new mode 100755 index 1cd1dd34c5..0e25c37863 --- a/interface/src/starfield/CMakeLists.txt +++ b/interface/src/starfield/CMakeLists.txt @@ -4,6 +4,6 @@ project(starfield) # Only headers (that are facaded by the Stars.cpp file) here - # 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}) diff --git a/interface/src/starfield/Config.h b/interface/src/starfield/Config.h old mode 100644 new mode 100755 index 3cbff171c7..d2d93be407 --- a/interface/src/starfield/Config.h +++ b/interface/src/starfield/Config.h @@ -9,30 +9,6 @@ #ifndef __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: // @@ -49,11 +25,6 @@ #include -#if STARFIELD_MULTITHREADING -#include -#include -#endif - #include #include #include @@ -88,14 +59,8 @@ namespace starfield { using namespace std; - -#if STARFIELD_SAVE_MEMORY - typedef uint16_t nuint; - typedef uint32_t wuint; -#else typedef uint32_t nuint; typedef uint64_t wuint; -#endif } diff --git a/interface/src/starfield/Controller.cpp b/interface/src/starfield/Controller.cpp new file mode 100755 index 0000000000..2ce2a071cb --- /dev/null +++ b/interface/src/starfield/Controller.cpp @@ -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); +} diff --git a/interface/src/starfield/Controller.h b/interface/src/starfield/Controller.h old mode 100644 new mode 100755 index 186a23c742..34cf9b46f3 --- a/interface/src/starfield/Controller.h +++ b/interface/src/starfield/Controller.h @@ -3,52 +3,17 @@ // interface // // Created by Tobias Schwinger on 3/29/13. +// Modified by Chris Barnard 10/16/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // #ifndef __interface__starfield__Controller__ #define __interface__starfield__Confroller__ -#ifndef __interface__Starfield_impl__ -#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 +#include "starfield/Generator.h" #include "starfield/data/InputVertex.h" -#include "starfield/data/BrightnessLevel.h" -#include "starfield/Loader.h" - #include "starfield/renderer/Renderer.h" #include "starfield/renderer/VertexOrder.h" @@ -57,371 +22,30 @@ namespace starfield { class Controller { public: - Controller() : - _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() : _tileResolution(20), _renderer(0l) { } ~Controller() { 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 - fraction = _lodFraction; - lwm = _lodLowWaterMark; - hwm = _lodHighWaterMark; - size_t last = _lodBrightnessSequence.size() - 1; + bool computeStars(unsigned numStars, unsigned seed); - // apply factor - fraction = max(0.0, min(1.0, fraction * factor)); + bool setResolution(unsigned tileResolution); - // 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 - 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 - } + void render(float perspective, float angle, mat4 const& orientation, float alpha); private: - void retile(size_t n, unsigned k, - BrightnessLevel b, BrightnessLevel bMin) { + void retile(unsigned numStars, unsigned tileResolution); - Tiling tiling(k); - VertexOrder scanner(tiling); - radix2InplaceSort(_inputSequence.begin(), _inputSequence.end(), scanner); + void recreateRenderer(unsigned numStars, unsigned tileResolution); -// printLog( -// "Stars.cpp: recreateRenderer(%d, %d, %d, %d)\n", n, k, b, bMin); - - recreateRenderer(n, k, b, bMin); - - _tileResolution = k; - } - - void recreateRenderer(size_t n, unsigned k, - BrightnessLevel b, BrightnessLevel bMin) { - -#if STARFIELD_MULTITHREADING - delete _renderer.exchange(new Renderer(_inputSequence, n, k, b, bMin) ); -#else - delete _renderer; - _renderer = new Renderer(_inputSequence, n, k, b, bMin); -#endif - } - - - static inline size_t toBufSize(double f) { - return size_t(floor(f + 0.5f)); - } - - struct BrightnessSortScanner : Radix2IntegerScanner { - - typedef Radix2IntegerScanner base; - - 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 _tileResolution; - - mutex _lodStateMutex; -#else - unsigned _tileResolution; -#endif - double _lodFraction; - double _lodLowWaterMark; - double _lodHighWaterMark; - double _lodOveralloc; - size_t _lodNalloc; - size_t _lodNRender; - BrightnessLevels _lodBrightnessSequence; - -#if STARFIELD_MULTITHREADING - atomic _lodBrightness; - BrightnessLevel _lodAllocBrightness; - - atomic _renderer; - - typedef lock_guard lock; -#else - BrightnessLevel _lodBrightness; - BrightnessLevel _lodAllocBrightness; - - Renderer* _renderer; - - #undef lock - #undef _ -#endif + InputVertices _inputSequence; + unsigned _tileResolution; + unsigned _numStars; + Renderer* _renderer; + }; } - - #endif diff --git a/interface/src/starfield/Generator.cpp b/interface/src/starfield/Generator.cpp new file mode 100644 index 0000000000..1e161a19cf --- /dev/null +++ b/interface/src/starfield/Generator.cpp @@ -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; +} \ No newline at end of file diff --git a/interface/src/starfield/Generator.h b/interface/src/starfield/Generator.h new file mode 100644 index 0000000000..1029bd6a52 --- /dev/null +++ b/interface/src/starfield/Generator.h @@ -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 +#include + +#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 \ No newline at end of file diff --git a/interface/src/starfield/data/BrightnessLevel.h b/interface/src/starfield/data/BrightnessLevel.h deleted file mode 100644 index 3567b88478..0000000000 --- a/interface/src/starfield/data/BrightnessLevel.h +++ /dev/null @@ -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 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 - diff --git a/interface/src/starfield/data/GpuVertex.cpp b/interface/src/starfield/data/GpuVertex.cpp new file mode 100755 index 0000000000..fdec1b85d2 --- /dev/null +++ b/interface/src/starfield/data/GpuVertex.cpp @@ -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); +} diff --git a/interface/src/starfield/data/GpuVertex.h b/interface/src/starfield/data/GpuVertex.h old mode 100644 new mode 100755 index c194e8cdb9..39eeb19634 --- a/interface/src/starfield/data/GpuVertex.h +++ b/interface/src/starfield/data/GpuVertex.h @@ -3,16 +3,13 @@ // interface // // Created by Tobias Schwinger on 3/29/13. +// Modified 10/17/13 Chris Barnard. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // #ifndef __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" namespace starfield { @@ -21,33 +18,18 @@ namespace starfield { public: GpuVertex() { } - GpuVertex(InputVertex const& in) { - - _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; - } + GpuVertex(InputVertex const& inputVertex); unsigned getColor() const { return _color; } private: - unsigned _color; - float _valX; - float _valY; - float _valZ; + unsigned _color; + float _valX; + float _valY; + float _valZ; }; -} // anonymous namespace +} #endif diff --git a/interface/src/starfield/data/InputVertex.cpp b/interface/src/starfield/data/InputVertex.cpp new file mode 100755 index 0000000000..28bffb0ec0 --- /dev/null +++ b/interface/src/starfield/data/InputVertex.cpp @@ -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(azimuth); + altitude = angleConvert(altitude); + + angleHorizontalPolar(azimuth, altitude); + + _azimuth = azimuth; + _altitude = altitude; +} diff --git a/interface/src/starfield/data/InputVertex.h b/interface/src/starfield/data/InputVertex.h old mode 100644 new mode 100755 index ca247a3ba4..d8c21a37a2 --- a/interface/src/starfield/data/InputVertex.h +++ b/interface/src/starfield/data/InputVertex.h @@ -3,16 +3,13 @@ // interface // // Created by Tobias Schwinger on 3/29/13. +// Modified by Chris Barnard 10/17/13. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // #ifndef __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" namespace starfield { @@ -20,33 +17,21 @@ namespace starfield { class InputVertex { public: - InputVertex(float azimuth, float altitude, unsigned color) { - - _color = ((color >> 16) & 0xffu) | (color & 0xff00u) | - ((color << 16) & 0xff0000u) | 0xff000000u; - - azimuth = angleConvert(azimuth); - altitude = angleConvert(altitude); - - angleHorizontalPolar(azimuth, altitude); - - _azimuth = azimuth; - _altitude = altitude; - } + InputVertex(float azimuth, float altitude, unsigned color); float getAzimuth() const { return _azimuth; } float getAltitude() const { return _altitude; } unsigned getColor() const { return _color; } private: - unsigned _color; - float _azimuth; - float _altitude; + unsigned _color; + float _azimuth; + float _altitude; }; typedef std::vector InputVertices; -} // anonymous namespace +} #endif diff --git a/interface/src/starfield/data/Tile.h b/interface/src/starfield/data/Tile.h old mode 100644 new mode 100755 index a7c26c7c8f..bdef4e612f --- a/interface/src/starfield/data/Tile.h +++ b/interface/src/starfield/data/Tile.h @@ -9,30 +9,22 @@ #ifndef __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/data/BrightnessLevel.h" namespace starfield { struct Tile { - - nuint offset; - nuint count; - BrightnessLevel lod; - nuint flags; + nuint offset; + nuint count; + nuint flags; // flags static uint16_t const checked = 1; static uint16_t const visited = 2; static uint16_t const render = 4; }; - - -} // anonymous namespace + +} #endif diff --git a/interface/src/starfield/renderer/Renderer.cpp b/interface/src/starfield/renderer/Renderer.cpp new file mode 100755 index 0000000000..d1a8cbab8d --- /dev/null +++ b/interface/src/starfield/renderer/Renderer.cpp @@ -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(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; +} \ No newline at end of file diff --git a/interface/src/starfield/renderer/Renderer.h b/interface/src/starfield/renderer/Renderer.h old mode 100644 new mode 100755 index 7eab70d178..7504dd0182 --- a/interface/src/starfield/renderer/Renderer.h +++ b/interface/src/starfield/renderer/Renderer.h @@ -3,24 +3,18 @@ // interface // // Created by Tobias Schwinger on 3/22/13. +// Modified 10/17/13 Chris Barnard. // Copyright (c) 2013 High Fidelity, Inc. All rights reserved. // #ifndef __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/data/InputVertex.h" -#include "starfield/data/BrightnessLevel.h" - #include "starfield/data/Tile.h" #include "starfield/data/GpuVertex.h" - -#include "Tiling.h" +#include "starfield/renderer/Tiling.h" // // FOV culling @@ -66,174 +60,14 @@ namespace starfield { class Renderer { public: - Renderer(InputVertices const& src, - size_t n, - unsigned k, - 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(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 - } - + Renderer(InputVertices const& src, unsigned numStars, unsigned tileResolution); + ~Renderer(); + void render(float perspective, float aspect, mat4 const& orientation, float alpha); + private: // renderer construction - void prepareVertexData(InputVertices const& src, - 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; - } - } + void prepareVertexData(InputVertices const& vertices, unsigned numStars, Tiling const& tiling); // FOV culling / LOD @@ -242,299 +76,65 @@ namespace starfield { class TileSelection { - public: - struct Cursor { Tile* current, * firstInRow; }; - private: - Renderer& _rendererRef; - Cursor* const _stackArray; - Cursor* _stackPos; - Tile const* const _tileArray; - Tile const* const _tilesEnd; + public: + struct Cursor { Tile* current, * firstInRow; }; + + private: + Renderer& _rendererRef; + Cursor* const _stackArray; + Cursor* _stackPos; + Tile const* const _tileArray; + Tile const* const _tilesEnd; - public: - - TileSelection(Renderer& renderer, Tile const* tiles, - Tile const* tiles_end, Cursor* stack) : - - _rendererRef(renderer), - _stackArray(stack), - _stackPos(stack), - _tileArray(tiles), - _tilesEnd(tiles_end) { - } + public: + TileSelection(Renderer& renderer, Tile const* tiles, Tile const* tiles_end, Cursor* stack) : + _rendererRef(renderer), + _stackArray(stack), + _stackPos(stack), + _tileArray(tiles), + _tilesEnd(tiles_end) { } - protected: - - // flood fill strategy - - bool select(Cursor const& c) { - Tile* t = c.current; - - if (t < _tileArray || t >= _tilesEnd || - !! (t->flags & Tile::checked)) { - - // 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; - } + protected: + bool select(Cursor const& cursor); + bool process(Cursor const& cursor); + void right(Cursor& cursor) const; + void left(Cursor& cursor) const; + void up(Cursor& cursor) const; + void down(Cursor& cursor) const; + void defer(Cursor const& cursor); + bool deferred(Cursor& cursor); }; - bool visitTile(Tile* t) { - - unsigned index = t - _tileArray; - *_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; - } - + bool visitTile(Tile* tile); + bool isTileVisible(unsigned index); + unsigned prepareBatch(unsigned const* indices, unsigned const* indicesEnd); + // GL API handling - void glAlloc() { - - GLchar const* const VERTEX_SHADER = - "#version 120\n" - "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(); - } - + void glAlloc(); + void glFree(); + void glUpload(GLsizei numStars); + void glBatch(GLfloat const* matrix, GLsizei n_ranges, float alpha); + // variables - GpuVertex* _dataArray; - Tile* _tileArray; - GLint* _batchOffs; - GLsizei* _batchCountArray; - GLuint _vertexArrayHandle; - ProgramObject _program; - int _alphaLocationHandle; + GpuVertex* _dataArray; + Tile* _tileArray; + GLint* _batchOffs; + GLsizei* _batchCountArray; + GLuint _vertexArrayHandle; + ProgramObject _program; + int _alphaLocationHandle; - Tiling _tiling; + Tiling _tiling; - unsigned* _outIndexPos; - vec3 _wRowVec; - float _halfPerspectiveAngle; - BrightnessLevel _minBright; + unsigned* _outIndexPos; + vec3 _wRowVec; + float _halfPerspectiveAngle; }; -} // anonymous namespace +} #endif diff --git a/interface/src/starfield/renderer/Tiling.h b/interface/src/starfield/renderer/Tiling.h old mode 100644 new mode 100755 index fdec54dfc7..7edbfd6656 --- a/interface/src/starfield/renderer/Tiling.h +++ b/interface/src/starfield/renderer/Tiling.h @@ -9,10 +9,6 @@ #ifndef __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" namespace starfield { @@ -20,53 +16,34 @@ namespace starfield { class Tiling { public: - Tiling(unsigned k) : - _valK(k), - _rcpSlice(k / Radians::twicePi()) { - _nBits = ceil(log(getTileCount()) * 1.4426950408889634); // log2 - } - - unsigned getAzimuthalTiles() const { return _valK; } - unsigned getAltitudinalTiles() const { return _valK / 2 + 1; } + Tiling(unsigned tileResolution) : _tileResolution(tileResolution), _rcpSlice(tileResolution / Radians::twicePi()) { + _nBits = ceil(log(getTileCount()) * LOG2); } + + unsigned getAzimuthalTiles() const { return _tileResolution; } + unsigned getAltitudinalTiles() const { return _tileResolution / 2 + 1; } unsigned getTileIndexBits() const { return _nBits; } - - unsigned getTileCount() const { - return getAzimuthalTiles() * getAltitudinalTiles(); - } - - unsigned getTileIndex(float azimuth, float altitude) const { - return discreteAzimuth(azimuth) + - _valK * discreteAltitude(altitude); - } - - float getSliceAngle() const { - return 1.0f / _rcpSlice; - } + unsigned getTileCount() const { return getAzimuthalTiles() * getAltitudinalTiles(); } + unsigned getTileIndex(float azimuth, float altitude) const { return discreteAzimuth(azimuth) + + _tileResolution * discreteAltitude(altitude); } + float getSliceAngle() const { return 1.0f / _rcpSlice; } private: - unsigned discreteAngle(float unsigned_angle) const { - - return unsigned(floor(unsigned_angle * _rcpSlice + 0.5f)); - } - - unsigned discreteAzimuth(float a) const { - return discreteAngle(a) % _valK; - } - - unsigned discreteAltitude(float a) const { - return min(getAltitudinalTiles() - 1, - discreteAngle(a + Radians::halfPi()) ); - } + unsigned discreteAngle(float unsigned_angle) const { return unsigned(floor(unsigned_angle * _rcpSlice + 0.5f)); } + unsigned discreteAzimuth(float angle) const { return discreteAngle(angle) % _tileResolution; } + unsigned discreteAltitude(float angle) const { return min( getAltitudinalTiles() - 1, + discreteAngle(angle + Radians::halfPi()) ); } // variables - unsigned _valK; - float _rcpSlice; - unsigned _nBits; + unsigned _tileResolution; + float _rcpSlice; + unsigned _nBits; + + const float LOG2 = 1.4426950408889634; }; -} // anonymous namespace +} #endif diff --git a/interface/src/starfield/renderer/VertexOrder.cpp b/interface/src/starfield/renderer/VertexOrder.cpp new file mode 100755 index 0000000000..78f5229f90 --- /dev/null +++ b/interface/src/starfield/renderer/VertexOrder.cpp @@ -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); +} \ No newline at end of file diff --git a/interface/src/starfield/renderer/VertexOrder.h b/interface/src/starfield/renderer/VertexOrder.h old mode 100644 new mode 100755 index d74864af18..85c738ce0d --- a/interface/src/starfield/renderer/VertexOrder.h +++ b/interface/src/starfield/renderer/VertexOrder.h @@ -9,37 +9,23 @@ #ifndef __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/data/InputVertex.h" #include "starfield/renderer/Tiling.h" namespace starfield { - /** - * Defines the vertex order for the renderer as a bit extractor for - * binary in-place Radix Sort. - */ + // Defines the vertex order for the renderer as a bit extractor for + //binary in-place Radix Sort. + class VertexOrder : public Radix2IntegerScanner { public: explicit VertexOrder(Tiling const& tiling) : - base(tiling.getTileIndexBits() + BrightnessBits), - _tiling(tiling) { - } + base(tiling.getTileIndexBits()), _tiling(tiling) { } - bool bit(InputVertex const& v, state_type const& s) 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); - } + bool bit(InputVertex const& vertex, state_type const& state) const; private: Tiling _tiling;