From 8778c07ccb8c13216d12bbd119061bb0aaefe6a7 Mon Sep 17 00:00:00 2001 From: Hleb Valoshka <375gnu@gmail.com> Date: Sun, 1 Dec 2019 15:32:10 +0300 Subject: [PATCH] Refactor render.cpp and extract some classes to own files --- src/celengine/CMakeLists.txt | 10 +- src/celengine/curveplot.h | 2 + src/celengine/hdrfuncrender.cpp | 443 +++++++++++ src/celengine/objectrenderer.h | 63 ++ src/celengine/orbitsampler.h | 48 ++ src/celengine/pointstarrenderer.cpp | 203 +++++ src/celengine/pointstarrenderer.h | 65 ++ src/celengine/pointstarvertexbuffer.cpp | 133 ++++ src/celengine/pointstarvertexbuffer.h | 75 ++ src/celengine/render.cpp | 968 +----------------------- src/celengine/render.h | 45 +- src/celengine/renderlistentry.h | 49 ++ 12 files changed, 1116 insertions(+), 988 deletions(-) create mode 100644 src/celengine/hdrfuncrender.cpp create mode 100644 src/celengine/objectrenderer.h create mode 100644 src/celengine/orbitsampler.h create mode 100644 src/celengine/pointstarrenderer.cpp create mode 100644 src/celengine/pointstarrenderer.h create mode 100644 src/celengine/pointstarvertexbuffer.cpp create mode 100644 src/celengine/pointstarvertexbuffer.h create mode 100644 src/celengine/renderlistentry.h diff --git a/src/celengine/CMakeLists.txt b/src/celengine/CMakeLists.txt index 8d269560..e3bc285b 100644 --- a/src/celengine/CMakeLists.txt +++ b/src/celengine/CMakeLists.txt @@ -47,6 +47,7 @@ set(CELENGINE_SOURCES globular.h glshader.cpp glshader.h + #hdrfuncrender.cpp image.cpp image.h lightenv.h @@ -66,11 +67,13 @@ set(CELENGINE_SOURCES name.h nebula.cpp nebula.h + objectrenderer.h observer.cpp observer.h octree.h opencluster.cpp opencluster.h + orbitsampler.h overlay.cpp overlay.h overlayimage.cpp @@ -85,15 +88,20 @@ set(CELENGINE_SOURCES # particlesystem.h planetgrid.cpp planetgrid.h + pointstarrenderer.cpp + pointstarrenderer.h + pointstarvertexbuffer.cpp + pointstarvertexbuffer.h rectangle.h referencemark.h rendcontext.cpp rendcontext.h render.cpp + render.h renderglsl.cpp renderglsl.h - render.h renderinfo.h + renderlistentry.h rotationmanager.cpp rotationmanager.h selection.cpp diff --git a/src/celengine/curveplot.h b/src/celengine/curveplot.h index da03babc..7c9ee2ba 100644 --- a/src/celengine/curveplot.h +++ b/src/celengine/curveplot.h @@ -27,6 +27,8 @@ // License and a copy of the GNU General Public License along with // orbitpath. If not, see . +#pragma once + #include #include diff --git a/src/celengine/hdrfuncrender.cpp b/src/celengine/hdrfuncrender.cpp new file mode 100644 index 00000000..7af91686 --- /dev/null +++ b/src/celengine/hdrfuncrender.cpp @@ -0,0 +1,443 @@ +// render.cpp +// +// Copyright (C) 2001-2009, the Celestia Development Team +// Original version by Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#ifdef USE_HDR +void Renderer::genBlurTextures() +{ + for (size_t i = 0; i < BLUR_PASS_COUNT; ++i) + { + if (blurTextures[i] != nullptr) + { + delete blurTextures[i]; + blurTextures[i] = nullptr; + } + } + if (blurTempTexture != nullptr) + { + delete blurTempTexture; + blurTempTexture = nullptr; + } + + blurBaseWidth = sceneTexWidth, blurBaseHeight = sceneTexHeight; + + if (blurBaseWidth > blurBaseHeight) + { + while (blurBaseWidth > BLUR_SIZE) + { + blurBaseWidth >>= 1; + blurBaseHeight >>= 1; + } + } + else + { + while (blurBaseHeight > BLUR_SIZE) + { + blurBaseWidth >>= 1; + blurBaseHeight >>= 1; + } + } + genBlurTexture(0); + genBlurTexture(1); + + Image *tempImg; + ImageTexture *tempTexture; + tempImg = new Image(GL_LUMINANCE, blurBaseWidth, blurBaseHeight); + tempTexture = new ImageTexture(*tempImg, Texture::EdgeClamp, Texture::DefaultMipMaps); + delete tempImg; + if (tempTexture && tempTexture->getName() != 0) + blurTempTexture = tempTexture; +} + +void Renderer::genBlurTexture(int blurLevel) +{ + Image *img; + ImageTexture *texture; + +#ifdef DEBUG_HDR + HDR_LOG << + "Window width = " << windowWidth << ", " << + "Window height = " << windowHeight << ", " << + "Blur tex width = " << (blurBaseWidth>>blurLevel) << ", " << + "Blur tex height = " << (blurBaseHeight>>blurLevel) << endl; +#endif + img = new Image(blurFormat, + blurBaseWidth>>blurLevel, + blurBaseHeight>>blurLevel); + texture = new ImageTexture(*img, + Texture::EdgeClamp, + Texture::NoMipMaps); + delete img; + + if (texture && texture->getName() != 0) + blurTextures[blurLevel] = texture; +} + +void Renderer::genSceneTexture() +{ + unsigned int *data; + if (sceneTexture != 0) + glDeleteTextures(1, &sceneTexture); + + sceneTexWidth = 1; + sceneTexHeight = 1; + while (sceneTexWidth < windowWidth) + sceneTexWidth <<= 1; + while (sceneTexHeight < windowHeight) + sceneTexHeight <<= 1; + sceneTexWScale = (windowWidth > 0) ? (GLfloat)sceneTexWidth / (GLfloat)windowWidth : + 1.0f; + sceneTexHScale = (windowHeight > 0) ? (GLfloat)sceneTexHeight / (GLfloat)windowHeight : + 1.0f; + data = (unsigned int* )malloc(sceneTexWidth*sceneTexHeight*4*sizeof(unsigned int)); + memset(data, 0, sceneTexWidth*sceneTexHeight*4*sizeof(unsigned int)); + + glGenTextures(1, &sceneTexture); + glBindTexture(GL_TEXTURE_2D, sceneTexture); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, sceneTexWidth, sceneTexHeight, 0, + GL_RGBA, GL_UNSIGNED_BYTE, data); + + free(data); +#ifdef DEBUG_HDR + static int genSceneTexCounter = 1; + HDR_LOG << + "[" << genSceneTexCounter++ << "] " << + "Window width = " << windowWidth << ", " << + "Window height = " << windowHeight << ", " << + "Tex width = " << sceneTexWidth << ", " << + "Tex height = " << sceneTexHeight << endl; +#endif +} + +void Renderer::renderToBlurTexture(int blurLevel) +{ + if (blurTextures[blurLevel] == nullptr) + return; + GLsizei blurTexWidth = blurBaseWidth>>blurLevel; + GLsizei blurTexHeight = blurBaseHeight>>blurLevel; + GLsizei blurDrawWidth = (GLfloat)windowWidth/(GLfloat)sceneTexWidth * blurTexWidth; + GLsizei blurDrawHeight = (GLfloat)windowHeight/(GLfloat)sceneTexHeight * blurTexHeight; + GLfloat blurWScale = 1.f; + GLfloat blurHScale = 1.f; + GLfloat savedWScale = 1.f; + GLfloat savedHScale = 1.f; + + glPushAttrib(GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT); + glClearColor(0, 0, 0, 1.f); + glViewport(0, 0, blurDrawWidth, blurDrawHeight); + glBindTexture(GL_TEXTURE_2D, sceneTexture); + + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, 0.0f, 1.0f); + glEnd(); + // Do not need to scale alpha so mask it off + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); + glEnable(GL_BLEND); + savedWScale = sceneTexWScale; + savedHScale = sceneTexHScale; + + // Remove ldr part of image + { + const GLfloat bias = -0.5f; + glBlendFunc(GL_ONE, GL_ONE); + glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); + glColor4f(-bias, -bias, -bias, 0.0f); + + glDisable(GL_TEXTURE_2D); + glBegin(GL_QUADS); + glVertex2f(0.0f, 0.0f); + glVertex2f(1.f, 0.0f); + glVertex2f(1.f, 1.f); + glVertex2f(0.0f, 1.f); + glEnd(); + + glEnable(GL_TEXTURE_2D); + blurTextures[blurLevel]->bind(); + glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, + blurTexWidth, blurTexHeight, 0); + } + + // Scale back up hdr part + { + glBlendEquationEXT(GL_FUNC_ADD_EXT); + glBlendFunc(GL_DST_COLOR, GL_ONE); + + glBegin(GL_QUADS); + drawBlendedVertices(0.f, 0.f, 1.f); //x2 + drawBlendedVertices(0.f, 0.f, 1.f); //x2 + glEnd(); + } + + glDisable(GL_BLEND); + + if (!useLuminanceAlpha) + { + blurTempTexture->bind(); + glCopyTexImage2D(GL_TEXTURE_2D, blurLevel, GL_LUMINANCE, 0, 0, + blurTexWidth, blurTexHeight, 0); + // Erase color, replace with luminance image + glBegin(GL_QUADS); + glColor4f(0.f, 0.f, 0.f, 1.f); + glVertex2f(0.0f, 0.0f); + glVertex2f(1.0f, 0.0f); + glVertex2f(1.0f, 1.0f); + glVertex2f(0.0f, 1.0f); + glEnd(); + glBegin(GL_QUADS); + drawBlendedVertices(0.f, 0.f, 1.f); + glEnd(); + } + + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + blurTextures[blurLevel]->bind(); + glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, + blurTexWidth, blurTexHeight, 0); +// blending end + + glClear(GL_COLOR_BUFFER_BIT); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + GLfloat xdelta = 1.0f / (GLfloat)blurTexWidth; + GLfloat ydelta = 1.0f / (GLfloat)blurTexHeight; + blurWScale = ((GLfloat)blurTexWidth / (GLfloat)blurDrawWidth); + blurHScale = ((GLfloat)blurTexHeight / (GLfloat)blurDrawHeight); + sceneTexWScale = blurWScale; + sceneTexHScale = blurHScale; + + // Butterworth low pass filter to reduce flickering dots + { + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, 0.0f, .5f*1.f); + drawBlendedVertices(-xdelta, 0.0f, .5f*0.333f); + drawBlendedVertices( xdelta, 0.0f, .5f*0.25f); + glEnd(); + glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, + blurTexWidth, blurTexHeight, 0); + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, -ydelta, .5f*0.667f); + drawBlendedVertices(0.0f, ydelta, .5f*0.333f); + glEnd(); + glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, + blurTexWidth, blurTexHeight, 0); + glClear(GL_COLOR_BUFFER_BIT); + } + + // Gaussian blur + switch (blurLevel) + { +/* + case 0: + drawGaussian3x3(xdelta, ydelta, blurTexWidth, blurTexHeight, 1.f); + break; +*/ +#ifdef __APPLE__ + case 0: + drawGaussian5x5(xdelta, ydelta, blurTexWidth, blurTexHeight, 1.f); + break; + case 1: + drawGaussian9x9(xdelta, ydelta, blurTexWidth, blurTexHeight, .3f); + break; +#else + // Gamma correct: windows=(mac^1.8)^(1/2.2) + case 0: + drawGaussian5x5(xdelta, ydelta, blurTexWidth, blurTexHeight, 1.f); + break; + case 1: + drawGaussian9x9(xdelta, ydelta, blurTexWidth, blurTexHeight, .373f); + break; +#endif + default: + break; + } + + blurTextures[blurLevel]->bind(); + glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, + blurTexWidth, blurTexHeight, 0); + + glDisable(GL_BLEND); + glClear(GL_COLOR_BUFFER_BIT); + glPopAttrib(); + sceneTexWScale = savedWScale; + sceneTexHScale = savedHScale; +} + +void Renderer::renderToTexture(const Observer& observer, + const Universe& universe, + float faintestMagNight, + const Selection& sel) +{ + if (sceneTexture == 0) + return; + glPushAttrib(GL_COLOR_BUFFER_BIT); + + draw(observer, universe, faintestMagNight, sel); + + glBindTexture(GL_TEXTURE_2D, sceneTexture); + glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, + sceneTexWidth, sceneTexHeight, 0); + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glPopAttrib(); +} + +void Renderer::drawSceneTexture() +{ + if (sceneTexture == 0) + return; + glBindTexture(GL_TEXTURE_2D, sceneTexture); + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, 0.0f, 1.0f); + glEnd(); +} + +void Renderer::drawBlendedVertices(float xdelta, float ydelta, float blend) +{ + glColor4f(1.0f, 1.0f, 1.0f, blend); + glTexCoord2i(0, 0); glVertex2f(xdelta, ydelta); + glTexCoord2i(1, 0); glVertex2f(sceneTexWScale+xdelta, ydelta); + glTexCoord2i(1, 1); glVertex2f(sceneTexWScale+xdelta, sceneTexHScale+ydelta); + glTexCoord2i(0, 1); glVertex2f(xdelta, sceneTexHScale+ydelta); +} + +void Renderer::drawGaussian3x3(float xdelta, float ydelta, GLsizei width, GLsizei height, float blend) +{ +#ifdef USE_BLOOM_LISTS + if (gaussianLists[0] == 0) + { + gaussianLists[0] = glGenLists(1); + glNewList(gaussianLists[0], GL_COMPILE); +#endif + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, 0.0f, blend); + drawBlendedVertices(-xdelta, 0.0f, 0.25f*blend); + drawBlendedVertices( xdelta, 0.0f, 0.20f*blend); + glEnd(); + + // Take result of horiz pass and apply vertical pass + glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, + width, height, 0); + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, -ydelta, 0.429f); + drawBlendedVertices(0.0f, ydelta, 0.300f); + glEnd(); +#ifdef USE_BLOOM_LISTS + glEndList(); + } + glCallList(gaussianLists[0]); +#endif +} + +void Renderer::drawGaussian5x5(float xdelta, float ydelta, GLsizei width, GLsizei height, float blend) +{ +#ifdef USE_BLOOM_LISTS + if (gaussianLists[1] == 0) + { + gaussianLists[1] = glGenLists(1); + glNewList(gaussianLists[1], GL_COMPILE); +#endif + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, 0.0f, blend); + drawBlendedVertices(-xdelta, 0.0f, 0.475f*blend); + drawBlendedVertices( xdelta, 0.0f, 0.475f*blend); + drawBlendedVertices(-2.0f*xdelta, 0.0f, 0.075f*blend); + drawBlendedVertices( 2.0f*xdelta, 0.0f, 0.075f*blend); + glEnd(); + glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, + width, height, 0); + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, -ydelta, 0.475f); + drawBlendedVertices(0.0f, ydelta, 0.475f); + drawBlendedVertices(0.0f, -2.0f*ydelta, 0.075f); + drawBlendedVertices(0.0f, 2.0f*ydelta, 0.075f); + glEnd(); +#ifdef USE_BLOOM_LISTS + glEndList(); + } + glCallList(gaussianLists[1]); +#endif +} + +void Renderer::drawGaussian9x9(float xdelta, float ydelta, GLsizei width, GLsizei height, float blend) +{ +#ifdef USE_BLOOM_LISTS + if (gaussianLists[2] == 0) + { + gaussianLists[2] = glGenLists(1); + glNewList(gaussianLists[2], GL_COMPILE); +#endif + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, 0.0f, blend); + drawBlendedVertices(-xdelta, 0.0f, 0.632f*blend); + drawBlendedVertices( xdelta, 0.0f, 0.632f*blend); + drawBlendedVertices(-2.0f*xdelta, 0.0f, 0.159f*blend); + drawBlendedVertices( 2.0f*xdelta, 0.0f, 0.159f*blend); + drawBlendedVertices(-3.0f*xdelta, 0.0f, 0.016f*blend); + drawBlendedVertices( 3.0f*xdelta, 0.0f, 0.016f*blend); + glEnd(); + + glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, + width, height, 0); + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, -ydelta, 0.632f); + drawBlendedVertices(0.0f, ydelta, 0.632f); + drawBlendedVertices(0.0f, -2.0f*ydelta, 0.159f); + drawBlendedVertices(0.0f, 2.0f*ydelta, 0.159f); + drawBlendedVertices(0.0f, -3.0f*ydelta, 0.016f); + drawBlendedVertices(0.0f, 3.0f*ydelta, 0.016f); + glEnd(); +#ifdef USE_BLOOM_LISTS + glEndList(); + } + glCallList(gaussianLists[2]); +#endif +} + +void Renderer::drawBlur() +{ + blurTextures[0]->bind(); + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, 0.0f, 1.0f); + glEnd(); + blurTextures[1]->bind(); + glBegin(GL_QUADS); + drawBlendedVertices(0.0f, 0.0f, 1.0f); + glEnd(); +} + +bool Renderer::getBloomEnabled() +{ + return bloomEnabled; +} + +void Renderer::setBloomEnabled(bool aBloomEnabled) +{ + bloomEnabled = aBloomEnabled; +} + +void Renderer::increaseBrightness() +{ + brightPlus += 1.0f; +} + +void Renderer::decreaseBrightness() +{ + brightPlus -= 1.0f; +} + +float Renderer::getBrightness() +{ + return brightPlus; +} +#endif // USE_HDR diff --git a/src/celengine/objectrenderer.h b/src/celengine/objectrenderer.h new file mode 100644 index 00000000..5a246194 --- /dev/null +++ b/src/celengine/objectrenderer.h @@ -0,0 +1,63 @@ +// objectrenderer.h +// +// Copyright (C) 2001-2019, the Celestia Development Team +// Original version by Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#pragma once + +#include +#include "octree.h" + +#ifdef USE_GLCONTEXT +class GLContext; +#endif +class Observer; +class Renderer; + +template class ObjectRenderer : public OctreeProcessor +{ + public: + ObjectRenderer(PREC _distanceLimit) : distanceLimit((float) _distanceLimit) {}; + void process(const OBJ& /*unused*/, PREC /*unused*/, float /*unused*/) {}; + + const Observer* observer { nullptr }; +#ifdef USE_GLCONTEXT + GLContext* context { nullptr }; +#endif + Renderer* renderer { nullptr }; + + Eigen::Vector3f viewNormal; + + float fov { 0.0f }; + float size { 0.0f }; + float pixelSize { 0.0f }; + float faintestMag { 0.0f }; + float faintestMagNight { 0.0f }; + float saturationMag { 0.0f }; +#ifdef USE_HDR + float exposure { 0.0f }; +#endif + float brightnessScale { 0.0f }; + float brightnessBias { 0.0f }; + float distanceLimit { 0.0f }; + + // Objects brighter than labelThresholdMag will be labeled + float labelThresholdMag { 0.0f }; + + // These are not fully used by this template's descendants + // but we place them here just in case a more sophisticated + // rendering scheme is implemented: + int nRendered { 0 }; + int nClose { 0 }; + int nBright { 0 }; + int nProcessed { 0 }; + int nLabelled { 0 }; + + uint64_t renderFlags { 0 }; + int labelMode { 0 }; +}; diff --git a/src/celengine/orbitsampler.h b/src/celengine/orbitsampler.h new file mode 100644 index 00000000..8cddace5 --- /dev/null +++ b/src/celengine/orbitsampler.h @@ -0,0 +1,48 @@ +// orbitsampler.h +// +// Copyright (C) 2001-2019, the Celestia Development Team +// Original version by Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#pragma once + +#include +#include +#include "curveplot.h" + +class OrbitSampler : public OrbitSampleProc +{ +public: + std::vector samples; + + OrbitSampler() = default; + + void sample(double t, const Eigen::Vector3d& position, const Eigen::Vector3d& velocity) + { + CurvePlotSample samp; + samp.t = t; + samp.position = position; + samp.velocity = velocity; + samples.push_back(samp); + } + + void insertForward(CurvePlot* plot) + { + for (const auto& sample : samples) + { + plot->addSample(sample); + } + } + + void insertBackward(CurvePlot* plot) + { + for (auto iter = samples.rbegin(); iter != samples.rend(); ++iter) + { + plot->addSample(*iter); + } + } +}; diff --git a/src/celengine/pointstarrenderer.cpp b/src/celengine/pointstarrenderer.cpp new file mode 100644 index 00000000..365eea0e --- /dev/null +++ b/src/celengine/pointstarrenderer.cpp @@ -0,0 +1,203 @@ +// pointstarrenderer.cpp +// +// Copyright (C) 2001-2019, the Celestia Development Team +// Original version by Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#include +#include +#include +#include "pointstarvertexbuffer.h" +#include "render.h" +#include "pointstarrenderer.h" + +using namespace std; +using namespace Eigen; + +// Convert a position in the universal coordinate system to astrocentric +// coordinates, taking into account possible orbital motion of the star. +static Vector3d astrocentricPosition(const UniversalCoord& pos, + const Star& star, + double t) +{ + return pos.offsetFromKm(star.getPosition(t)); +} + +PointStarRenderer::PointStarRenderer() : + ObjectRenderer(StarDistanceLimit) +{ +} + +void PointStarRenderer::process(const Star& star, float distance, float appMag) +{ + nProcessed++; + + Vector3f starPos = star.getPosition(); + + // Calculate the difference at double precision *before* converting to float. + // This is very important for stars that are far from the origin. + Vector3f relPos = (starPos.cast() - obsPos).cast(); + float orbitalRadius = star.getOrbitalRadius(); + bool hasOrbit = orbitalRadius > 0.0f; + + if (distance > distanceLimit) + return; + + // A very rough check to see if the star may be visible: is the star in + // front of the viewer? If the star might be close (relPos.x^2 < 0.1) or + // is moving in an orbit, we'll always regard it as potentially visible. + // TODO: consider normalizing relPos and comparing relPos*viewNormal against + // cosFOV--this will cull many more stars than relPos*viewNormal, at the + // cost of a normalize per star. + if (relPos.dot(viewNormal) > 0.0f || relPos.x() * relPos.x() < 0.1f || hasOrbit) + { +#ifdef HDR_COMPRESS + Color starColorFull = colorTemp->lookupColor(star.getTemperature()); + Color starColor(starColorFull.red() * 0.5f, + starColorFull.green() * 0.5f, + starColorFull.blue() * 0.5f); +#else + Color starColor = colorTemp->lookupColor(star.getTemperature()); +#endif + float discSizeInPixels = 0.0f; + float orbitSizeInPixels = 0.0f; + + if (hasOrbit) + orbitSizeInPixels = orbitalRadius / (distance * pixelSize); + + // Special handling for stars less than one light year away . . . + // We can't just go ahead and render a nearby star in the usual way + // for two reasons: + // * It may be clipped by the near plane + // * It may be large enough that we should render it as a mesh + // instead of a particle + // It's possible that the second condition might apply for stars + // further than one light year away if the star is huge, the fov is + // very small and the resolution is high. We'll ignore this for now + // and use the most inexpensive test possible . . . + if (distance < 1.0f || orbitSizeInPixels > 1.0f) + { + // Compute the position of the observer relative to the star. + // This is a much more accurate (and expensive) distance + // calculation than the previous one which used the observer's + // position rounded off to floats. + Vector3d hPos = astrocentricPosition(observer->getPosition(), + star, + observer->getTime()); + relPos = hPos.cast() * -astro::kilometersToLightYears(1.0f); + distance = relPos.norm(); + + // Recompute apparent magnitude using new distance computation + appMag = astro::absToAppMag(star.getAbsoluteMagnitude(), distance); + + discSizeInPixels = star.getRadius() / astro::lightYearsToKilometers(distance) / pixelSize; + ++nClose; + } + + // Place labels for stars brighter than the specified label threshold brightness + if (((labelMode & Renderer::StarLabels) != 0) && appMag < labelThresholdMag) + { + Vector3f starDir = relPos; + starDir.normalize(); + if (starDir.dot(viewNormal) > cosFOV) + { + float distr = 3.5f * (labelThresholdMag - appMag)/labelThresholdMag; + if (distr > 1.0f) + distr = 1.0f; + renderer->addBackgroundAnnotation(nullptr, starDB->getStarName(star, true), + Color(Renderer::StarLabelColor, distr * Renderer::StarLabelColor.alpha()), + relPos); + nLabelled++; + } + } + // Stars closer than the maximum solar system size are actually + // added to the render list and depth sorted, since they may occlude + // planets. + if (distance > SolarSystemMaxDistance) + { +#ifdef USE_HDR + float satPoint = saturationMag; + float alpha = exposure*(faintestMag - appMag)/(faintestMag - saturationMag + 0.001f); +#else + float satPoint = faintestMag - (1.0f - brightnessBias) / brightnessScale; // TODO: precompute this value + float alpha = (faintestMag - appMag) * brightnessScale + brightnessBias; +#endif +#ifdef DEBUG_HDR_ADAPT + minMag = max(minMag, appMag); + maxMag = min(maxMag, appMag); + minAlpha = min(minAlpha, alpha); + maxAlpha = max(maxAlpha, alpha); + ++total; + if (alpha > above) + { + ++countAboveN; + } +#endif + + if (useScaledDiscs) + { + float discSize = size; + if (alpha < 0.0f) + { + alpha = 0.0f; + } + else if (alpha > 1.0f) + { + float discScale = min(MaxScaledDiscStarSize, (float) pow(2.0f, 0.3f * (satPoint - appMag))); + discSize *= discScale; + + float glareAlpha = min(0.5f, discScale / 4.0f); + glareVertexBuffer->addStar(relPos, Color(starColor, glareAlpha), discSize * 3.0f); + + alpha = 1.0f; + } + starVertexBuffer->addStar(relPos, Color(starColor, alpha), discSize); + } + else + { + if (alpha < 0.0f) + { + alpha = 0.0f; + } + else if (alpha > 1.0f) + { + float discScale = min(100.0f, satPoint - appMag + 2.0f); + float glareAlpha = min(GlareOpacity, (discScale - 2.0f) / 4.0f); + glareVertexBuffer->addStar(relPos, Color(starColor, glareAlpha), 2.0f * discScale * size); +#ifdef DEBUG_HDR_ADAPT + maxSize = max(maxSize, 2.0f * discScale * size); +#endif + } + starVertexBuffer->addStar(relPos, Color(starColor, alpha), size); + } + + ++nRendered; + } + else + { + Matrix3f viewMat = observer->getOrientationf().toRotationMatrix(); + Vector3f viewMatZ = viewMat.row(2); + + RenderListEntry rle; + rle.renderableType = RenderListEntry::RenderableStar; + rle.star = ☆ + + // Objects in the render list are always rendered relative to + // a viewer at the origin--this is different than for distant + // stars. + float scale = astro::lightYearsToKilometers(1.0f); + rle.position = relPos * scale; + rle.centerZ = rle.position.dot(viewMatZ); + rle.distance = rle.position.norm(); + rle.radius = star.getRadius(); + rle.discSizeInPixels = discSizeInPixels; + rle.appMag = appMag; + rle.isOpaque = true; + renderList->push_back(rle); + } + } +} diff --git a/src/celengine/pointstarrenderer.h b/src/celengine/pointstarrenderer.h new file mode 100644 index 00000000..07de945d --- /dev/null +++ b/src/celengine/pointstarrenderer.h @@ -0,0 +1,65 @@ +// pointstarrenderer.h +// +// Copyright (C) 2001-2019, the Celestia Development Team +// Original version by Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#pragma once + +#include +#include +#include "objectrenderer.h" +#include "renderlistentry.h" + +class ColorTemperatureTable; +class PointStarVertexBuffer; +class Star; +class StarDatabase; + +// TODO: move these variables to PointStarRenderer class +// without adding a variable. Requires C++17 +constexpr const float StarDistanceLimit = 1.0e6f; +// Star disc size in pixels +constexpr const float BaseStarDiscSize = 5.0f; +constexpr const float MaxScaledDiscStarSize = 8.0f; +constexpr const float GlareOpacity = 0.65f; + +class PointStarRenderer : public ObjectRenderer +{ + public: +#if 0 + static constexpr const float StarDistanceLimit = 1.0e6f; + // Star disc size in pixels + static constexpr const float BaseStarDiscSize = 5.0f; + static constexpr const float MaxScaledDiscStarSize = 8.0f; + static constexpr const float GlareOpacity = 0.65f; +#endif + + PointStarRenderer(); + void process(const Star &star, float distance, float appMag); + + Eigen::Vector3d obsPos; + std::vector* renderList { nullptr }; + PointStarVertexBuffer* starVertexBuffer { nullptr }; + PointStarVertexBuffer* glareVertexBuffer { nullptr }; + const StarDatabase* starDB { nullptr }; + const ColorTemperatureTable* colorTemp { nullptr }; + float SolarSystemMaxDistance { 1.0f }; + float maxDiscSize { 1.0f }; + float cosFOV { 1.0f }; +#ifdef DEBUG_HDR_ADAPT + float minMag { 0.0f }; + float maxMag { 0.0f }; + float minAlpha { 0.0f }; + float maxAlpha { 0.0f }; + float maxSize { 0.0f }; + float above { 0.0f }; + unsigned long countAboveN { 0 }; + unsigned long total { 0 }; +#endif + bool useScaledDiscs { false }; +}; diff --git a/src/celengine/pointstarvertexbuffer.cpp b/src/celengine/pointstarvertexbuffer.cpp new file mode 100644 index 00000000..ad3e5cad --- /dev/null +++ b/src/celengine/pointstarvertexbuffer.cpp @@ -0,0 +1,133 @@ +// starfield.cpp +// +// Copyright (C) 2001-2019, the Celestia Development Team +// Original version by Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#include +#include +#include "objectrenderer.h" +#include "shadermanager.h" +#include "render.h" +#include "texture.h" +#include "pointstarvertexbuffer.h" + + +PointStarVertexBuffer::PointStarVertexBuffer(const Renderer& _renderer, + unsigned int _capacity) : + renderer(_renderer), + capacity(_capacity) +{ + vertices = new StarVertex[capacity]; +} + +PointStarVertexBuffer::~PointStarVertexBuffer() +{ + delete[] vertices; +} + +void PointStarVertexBuffer::startSprites() +{ + auto *prog = renderer.getShaderManager().getShader("star"); + if (prog == nullptr) + return; + prog->use(); + prog->samplerParam("starTex") = 0; + + unsigned int stride = sizeof(StarVertex); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, stride, &vertices[0].position); + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, GL_UNSIGNED_BYTE, stride, &vertices[0].color); + + glEnableVertexAttribArray(CelestiaGLProgram::PointSizeAttributeIndex); + glVertexAttribPointer(CelestiaGLProgram::PointSizeAttributeIndex, + 1, GL_FLOAT, GL_FALSE, + stride, &vertices[0].size); + + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + + glEnable(GL_POINT_SPRITE); + + useSprites = true; +} + +void PointStarVertexBuffer::startPoints() +{ + auto *prog = renderer.getShaderManager().getShader(ShaderProperties::PerVertexColor); + if (prog == nullptr) + return; + prog->use(); + + unsigned int stride = sizeof(StarVertex); + glEnableClientState(GL_VERTEX_ARRAY); + glVertexPointer(3, GL_FLOAT, stride, &vertices[0].position); + glEnableClientState(GL_COLOR_ARRAY); + glColorPointer(4, GL_UNSIGNED_BYTE, stride, &vertices[0].color); + + // An option to control the size of the stars would be helpful. + // Which size looks best depends a lot on the resolution and the + // type of display device. + // glPointSize(2.0f); + // glEnable(GL_POINT_SMOOTH); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glDisableClientState(GL_NORMAL_ARRAY); + + useSprites = false; +} + +void PointStarVertexBuffer::render() +{ + if (nStars != 0) + { + unsigned int stride = sizeof(StarVertex); + if (useSprites) + { + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); + } + else + { + glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); + glPointSize(1.0f); + } + glVertexPointer(3, GL_FLOAT, stride, &vertices[0].position); + glColorPointer(4, GL_UNSIGNED_BYTE, stride, &vertices[0].color); + + if (useSprites) + { + glVertexAttribPointer(CelestiaGLProgram::PointSizeAttributeIndex, + 1, GL_FLOAT, GL_FALSE, + stride, &vertices[0].size); + } + + if (texture != nullptr) + texture->bind(); + glDrawArrays(GL_POINTS, 0, nStars); + nStars = 0; + } +} + +void PointStarVertexBuffer::finish() +{ + render(); + glDisableClientState(GL_COLOR_ARRAY); + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + if (useSprites) + { + glDisableVertexAttribArray(CelestiaGLProgram::PointSizeAttributeIndex); + glDisable(GL_POINT_SPRITE); + } + glUseProgram(0); +} + +void PointStarVertexBuffer::setTexture(Texture* _texture) +{ + texture = _texture; +} diff --git a/src/celengine/pointstarvertexbuffer.h b/src/celengine/pointstarvertexbuffer.h new file mode 100644 index 00000000..0aca7206 --- /dev/null +++ b/src/celengine/pointstarvertexbuffer.h @@ -0,0 +1,75 @@ +// pointstarvertexbuffer.h +// +// Copyright (C) 2001-2019, the Celestia Development Team +// Original version by Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#pragma once + +#include + +class Color; +class Renderer; +class Texture; + +// PointStarVertexBuffer is used when hardware supports point sprites. +class PointStarVertexBuffer +{ +public: + using capacity_t = unsigned int; + + PointStarVertexBuffer(const Renderer& _renderer, unsigned int _capacity); + ~PointStarVertexBuffer(); + PointStarVertexBuffer() = delete; + PointStarVertexBuffer(const PointStarVertexBuffer&) = delete; + PointStarVertexBuffer(PointStarVertexBuffer&&) = delete; + PointStarVertexBuffer& operator=(const PointStarVertexBuffer&) = delete; + PointStarVertexBuffer& operator=(PointStarVertexBuffer&&) = delete; + + void startPoints(); + void startSprites(); + void render(); + void finish(); + inline void addStar(const Eigen::Vector3f& pos, const Color&, float); + void setTexture(Texture* /*_texture*/); + +private: + struct StarVertex + { + Eigen::Vector3f position; + float size; + unsigned char color[4]; + float pad; + }; + + const Renderer& renderer; + capacity_t capacity; + + capacity_t nStars { 0 }; + StarVertex* vertices { nullptr }; + Texture* texture { nullptr }; + bool useSprites { false }; +}; + +inline void PointStarVertexBuffer::addStar(const Eigen::Vector3f& pos, + const Color& color, + float size) +{ + if (nStars < capacity) + { + vertices[nStars].position = pos; + vertices[nStars].size = size; + color.get(vertices[nStars].color); + nStars++; + } + + if (nStars == capacity) + { + render(); + nStars = 0; + } +} diff --git a/src/celengine/render.cpp b/src/celengine/render.cpp index a2672f0e..2466f1a8 100644 --- a/src/celengine/render.cpp +++ b/src/celengine/render.cpp @@ -59,6 +59,9 @@ std::ofstream hdrlog; #include "curveplot.h" #include "shadermanager.h" #include "rectangle.h" +#include "pointstarvertexbuffer.h" +#include "pointstarrenderer.h" +#include "orbitsampler.h" #include #include #include @@ -93,7 +96,6 @@ using namespace celmath; #define NEAR_DIST 0.5f #define FAR_DIST 1.0e9f -static const float STAR_DISTANCE_LIMIT = 1.0e6f; static const int REF_DISTANCE_TO_SCREEN = 400; //[mm] // Contribution from planetshine beyond this distance (in units of object radius) @@ -118,13 +120,6 @@ static const float PixelOffset = 0.125f; static const float MinNearPlaneDistance = 0.0001f; // km static const float MaxFarNearRatio = 2000000.0f; -static const float RenderDistance = 50.0f; - -// Star disc size in pixels -static const float BaseStarDiscSize = 5.0f; -static const float MaxScaledDiscStarSize = 8.0f; -static const float GlareOpacity = 0.65f; - static const float MinRelativeOccluderRadius = 0.005f; static const float CubeCornerToCenterDistance = (float) sqrt(3.0); @@ -275,174 +270,6 @@ double computeCosViewConeAngle(double verticalFOV, double width, double height) return 1.0 / diag; } -// PointStarVertexBuffer is used when hardware supports point sprites. -class PointStarVertexBuffer -{ -public: - PointStarVertexBuffer(const Renderer& _renderer, unsigned int _capacity); - ~PointStarVertexBuffer(); - void startPoints(); - void startSprites(); - void render(); - void finish(); - inline void addStar(const Eigen::Vector3f& pos, const Color&, float); - void setTexture(Texture* /*_texture*/); - -private: - struct StarVertex - { - Eigen::Vector3f position; - float size; - unsigned char color[4]; - float pad; - }; - - const Renderer& renderer; - unsigned int capacity; - unsigned int nStars{ 0 }; - StarVertex* vertices{ nullptr }; - bool useSprites{ false }; - Texture* texture{ nullptr }; -}; - -PointStarVertexBuffer::PointStarVertexBuffer(const Renderer& _renderer, - unsigned int _capacity) : - renderer(_renderer), - capacity(_capacity) -{ - vertices = new StarVertex[capacity]; -} - -PointStarVertexBuffer::~PointStarVertexBuffer() -{ - delete[] vertices; -} - -void PointStarVertexBuffer::startSprites() -{ - auto *prog = renderer.getShaderManager().getShader("star"); - if (prog == nullptr) - return; - prog->use(); - prog->samplerParam("starTex") = 0; - - unsigned int stride = sizeof(StarVertex); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, stride, &vertices[0].position); - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_UNSIGNED_BYTE, stride, &vertices[0].color); - - glEnableVertexAttribArray(CelestiaGLProgram::PointSizeAttributeIndex); - glVertexAttribPointer(CelestiaGLProgram::PointSizeAttributeIndex, - 1, GL_FLOAT, GL_FALSE, - stride, &vertices[0].size); - - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisableClientState(GL_NORMAL_ARRAY); - - glEnable(GL_POINT_SPRITE); - - useSprites = true; -} - -void PointStarVertexBuffer::startPoints() -{ - auto *prog = renderer.getShaderManager().getShader(ShaderProperties::PerVertexColor); - if (prog == nullptr) - return; - prog->use(); - - unsigned int stride = sizeof(StarVertex); - glEnableClientState(GL_VERTEX_ARRAY); - glVertexPointer(3, GL_FLOAT, stride, &vertices[0].position); - glEnableClientState(GL_COLOR_ARRAY); - glColorPointer(4, GL_UNSIGNED_BYTE, stride, &vertices[0].color); - - // An option to control the size of the stars would be helpful. - // Which size looks best depends a lot on the resolution and the - // type of display device. - // glPointSize(2.0f); - // glEnable(GL_POINT_SMOOTH); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glDisable(GL_TEXTURE_2D); - - glDisableClientState(GL_NORMAL_ARRAY); - - useSprites = false; -} - -void PointStarVertexBuffer::render() -{ - if (nStars != 0) - { - unsigned int stride = sizeof(StarVertex); - if (useSprites) - { - glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); - } - else - { - glDisable(GL_VERTEX_PROGRAM_POINT_SIZE); - glPointSize(1.0f); - } - glVertexPointer(3, GL_FLOAT, stride, &vertices[0].position); - glColorPointer(4, GL_UNSIGNED_BYTE, stride, &vertices[0].color); - - if (useSprites) - { - glVertexAttribPointer(CelestiaGLProgram::PointSizeAttributeIndex, - 1, GL_FLOAT, GL_FALSE, - stride, &vertices[0].size); - } - - if (texture != nullptr) - texture->bind(); - glDrawArrays(GL_POINTS, 0, nStars); - nStars = 0; - } -} - -void PointStarVertexBuffer::finish() -{ - render(); - glDisableClientState(GL_COLOR_ARRAY); - glDisableClientState(GL_VERTEX_ARRAY); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - - if (useSprites) - { - glDisableVertexAttribArray(CelestiaGLProgram::PointSizeAttributeIndex); - glDisable(GL_POINT_SPRITE); - } - glUseProgram(0); -} - -inline void PointStarVertexBuffer::addStar(const Eigen::Vector3f& pos, - const Color& color, - float size) -{ - if (nStars < capacity) - { - vertices[nStars].position = pos; - vertices[nStars].size = size; - color.get(vertices[nStars].color); - nStars++; - } - - if (nStars == capacity) - { - render(); - nStars = 0; - } -} - -void PointStarVertexBuffer::setTexture(Texture* _texture) -{ - texture = _texture; -} - -/**** End star vertex buffer classes ****/ - Renderer::Renderer() : windowWidth(0), @@ -1458,40 +1285,6 @@ inline void disableSmoothLines(uint64_t renderFlags) disableSmoothLines(); } -class OrbitSampler : public OrbitSampleProc -{ -public: - vector samples; - - OrbitSampler() = default; - - void sample(double t, const Vector3d& position, const Vector3d& velocity) - { - CurvePlotSample samp; - samp.t = t; - samp.position = position; - samp.velocity = velocity; - samples.push_back(samp); - } - - void insertForward(CurvePlot* plot) - { - for (const auto& sample : samples) - { - plot->addSample(sample); - } - } - - void insertBackward(CurvePlot* plot) - { - for (auto iter = samples.rbegin(); iter != samples.rend(); ++iter) - { - plot->addSample(*iter); - } - } -}; - - Vector4f renderOrbitColor(const Body *body, bool selected, float opacity) { Color orbitColor; @@ -1860,7 +1653,7 @@ setupLightSources(const vector& nearStars, ls.luminosity = star->getLuminosity(); ls.radius = star->getRadius(); - if (renderFlags & Renderer::ShowTintedIllumination) + if ((renderFlags & Renderer::ShowTintedIllumination) != 0) { // If the star is sufficiently cool, change the light color // from white. Though our sun appears yellow, we still make @@ -1966,440 +1759,6 @@ void Renderer::renderItem(const RenderListEntry& rle, } -#ifdef USE_HDR -void Renderer::genBlurTextures() -{ - for (size_t i = 0; i < BLUR_PASS_COUNT; ++i) - { - if (blurTextures[i] != nullptr) - { - delete blurTextures[i]; - blurTextures[i] = nullptr; - } - } - if (blurTempTexture) - { - delete blurTempTexture; - blurTempTexture = nullptr; - } - - blurBaseWidth = sceneTexWidth, blurBaseHeight = sceneTexHeight; - - if (blurBaseWidth > blurBaseHeight) - { - while (blurBaseWidth > BLUR_SIZE) - { - blurBaseWidth >>= 1; - blurBaseHeight >>= 1; - } - } - else - { - while (blurBaseHeight > BLUR_SIZE) - { - blurBaseWidth >>= 1; - blurBaseHeight >>= 1; - } - } - genBlurTexture(0); - genBlurTexture(1); - - Image *tempImg; - ImageTexture *tempTexture; - tempImg = new Image(GL_LUMINANCE, blurBaseWidth, blurBaseHeight); - tempTexture = new ImageTexture(*tempImg, Texture::EdgeClamp, Texture::DefaultMipMaps); - delete tempImg; - if (tempTexture && tempTexture->getName() != 0) - blurTempTexture = tempTexture; -} - -void Renderer::genBlurTexture(int blurLevel) -{ - Image *img; - ImageTexture *texture; - -#ifdef DEBUG_HDR - HDR_LOG << - "Window width = " << windowWidth << ", " << - "Window height = " << windowHeight << ", " << - "Blur tex width = " << (blurBaseWidth>>blurLevel) << ", " << - "Blur tex height = " << (blurBaseHeight>>blurLevel) << endl; -#endif - img = new Image(blurFormat, - blurBaseWidth>>blurLevel, - blurBaseHeight>>blurLevel); - texture = new ImageTexture(*img, - Texture::EdgeClamp, - Texture::NoMipMaps); - delete img; - - if (texture && texture->getName() != 0) - blurTextures[blurLevel] = texture; -} - -void Renderer::genSceneTexture() -{ - unsigned int *data; - if (sceneTexture != 0) - glDeleteTextures(1, &sceneTexture); - - sceneTexWidth = 1; - sceneTexHeight = 1; - while (sceneTexWidth < windowWidth) - sceneTexWidth <<= 1; - while (sceneTexHeight < windowHeight) - sceneTexHeight <<= 1; - sceneTexWScale = (windowWidth > 0) ? (GLfloat)sceneTexWidth / (GLfloat)windowWidth : - 1.0f; - sceneTexHScale = (windowHeight > 0) ? (GLfloat)sceneTexHeight / (GLfloat)windowHeight : - 1.0f; - data = (unsigned int* )malloc(sceneTexWidth*sceneTexHeight*4*sizeof(unsigned int)); - memset(data, 0, sceneTexWidth*sceneTexHeight*4*sizeof(unsigned int)); - - glGenTextures(1, &sceneTexture); - glBindTexture(GL_TEXTURE_2D, sceneTexture); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, sceneTexWidth, sceneTexHeight, 0, - GL_RGBA, GL_UNSIGNED_BYTE, data); - - free(data); -#ifdef DEBUG_HDR - static int genSceneTexCounter = 1; - HDR_LOG << - "[" << genSceneTexCounter++ << "] " << - "Window width = " << windowWidth << ", " << - "Window height = " << windowHeight << ", " << - "Tex width = " << sceneTexWidth << ", " << - "Tex height = " << sceneTexHeight << endl; -#endif -} - -void Renderer::renderToBlurTexture(int blurLevel) -{ - if (blurTextures[blurLevel] == nullptr) - return; - GLsizei blurTexWidth = blurBaseWidth>>blurLevel; - GLsizei blurTexHeight = blurBaseHeight>>blurLevel; - GLsizei blurDrawWidth = (GLfloat)windowWidth/(GLfloat)sceneTexWidth * blurTexWidth; - GLsizei blurDrawHeight = (GLfloat)windowHeight/(GLfloat)sceneTexHeight * blurTexHeight; - GLfloat blurWScale = 1.f; - GLfloat blurHScale = 1.f; - GLfloat savedWScale = 1.f; - GLfloat savedHScale = 1.f; - - glPushAttrib(GL_COLOR_BUFFER_BIT | GL_VIEWPORT_BIT); - glClearColor(0, 0, 0, 1.f); - glViewport(0, 0, blurDrawWidth, blurDrawHeight); - glBindTexture(GL_TEXTURE_2D, sceneTexture); - - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, 0.0f, 1.0f); - glEnd(); - // Do not need to scale alpha so mask it off - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); - glEnable(GL_BLEND); - savedWScale = sceneTexWScale; - savedHScale = sceneTexHScale; - - // Remove ldr part of image - { - const GLfloat bias = -0.5f; - glBlendFunc(GL_ONE, GL_ONE); - glBlendEquationEXT(GL_FUNC_REVERSE_SUBTRACT_EXT); - glColor4f(-bias, -bias, -bias, 0.0f); - - glDisable(GL_TEXTURE_2D); - glBegin(GL_QUADS); - glVertex2f(0.0f, 0.0f); - glVertex2f(1.f, 0.0f); - glVertex2f(1.f, 1.f); - glVertex2f(0.0f, 1.f); - glEnd(); - - glEnable(GL_TEXTURE_2D); - blurTextures[blurLevel]->bind(); - glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, - blurTexWidth, blurTexHeight, 0); - } - - // Scale back up hdr part - { - glBlendEquationEXT(GL_FUNC_ADD_EXT); - glBlendFunc(GL_DST_COLOR, GL_ONE); - - glBegin(GL_QUADS); - drawBlendedVertices(0.f, 0.f, 1.f); //x2 - drawBlendedVertices(0.f, 0.f, 1.f); //x2 - glEnd(); - } - - glDisable(GL_BLEND); - - if (!useLuminanceAlpha) - { - blurTempTexture->bind(); - glCopyTexImage2D(GL_TEXTURE_2D, blurLevel, GL_LUMINANCE, 0, 0, - blurTexWidth, blurTexHeight, 0); - // Erase color, replace with luminance image - glBegin(GL_QUADS); - glColor4f(0.f, 0.f, 0.f, 1.f); - glVertex2f(0.0f, 0.0f); - glVertex2f(1.0f, 0.0f); - glVertex2f(1.0f, 1.0f); - glVertex2f(0.0f, 1.0f); - glEnd(); - glBegin(GL_QUADS); - drawBlendedVertices(0.f, 0.f, 1.f); - glEnd(); - } - - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - blurTextures[blurLevel]->bind(); - glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, - blurTexWidth, blurTexHeight, 0); -// blending end - - glClear(GL_COLOR_BUFFER_BIT); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - GLfloat xdelta = 1.0f / (GLfloat)blurTexWidth; - GLfloat ydelta = 1.0f / (GLfloat)blurTexHeight; - blurWScale = ((GLfloat)blurTexWidth / (GLfloat)blurDrawWidth); - blurHScale = ((GLfloat)blurTexHeight / (GLfloat)blurDrawHeight); - sceneTexWScale = blurWScale; - sceneTexHScale = blurHScale; - - // Butterworth low pass filter to reduce flickering dots - { - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, 0.0f, .5f*1.f); - drawBlendedVertices(-xdelta, 0.0f, .5f*0.333f); - drawBlendedVertices( xdelta, 0.0f, .5f*0.25f); - glEnd(); - glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, - blurTexWidth, blurTexHeight, 0); - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, -ydelta, .5f*0.667f); - drawBlendedVertices(0.0f, ydelta, .5f*0.333f); - glEnd(); - glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, - blurTexWidth, blurTexHeight, 0); - glClear(GL_COLOR_BUFFER_BIT); - } - - // Gaussian blur - switch (blurLevel) - { -/* - case 0: - drawGaussian3x3(xdelta, ydelta, blurTexWidth, blurTexHeight, 1.f); - break; -*/ -#ifdef __APPLE__ - case 0: - drawGaussian5x5(xdelta, ydelta, blurTexWidth, blurTexHeight, 1.f); - break; - case 1: - drawGaussian9x9(xdelta, ydelta, blurTexWidth, blurTexHeight, .3f); - break; -#else - // Gamma correct: windows=(mac^1.8)^(1/2.2) - case 0: - drawGaussian5x5(xdelta, ydelta, blurTexWidth, blurTexHeight, 1.f); - break; - case 1: - drawGaussian9x9(xdelta, ydelta, blurTexWidth, blurTexHeight, .373f); - break; -#endif - default: - break; - } - - blurTextures[blurLevel]->bind(); - glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, - blurTexWidth, blurTexHeight, 0); - - glDisable(GL_BLEND); - glClear(GL_COLOR_BUFFER_BIT); - glPopAttrib(); - sceneTexWScale = savedWScale; - sceneTexHScale = savedHScale; -} - -void Renderer::renderToTexture(const Observer& observer, - const Universe& universe, - float faintestMagNight, - const Selection& sel) -{ - if (sceneTexture == 0) - return; - glPushAttrib(GL_COLOR_BUFFER_BIT); - - draw(observer, universe, faintestMagNight, sel); - - glBindTexture(GL_TEXTURE_2D, sceneTexture); - glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, - sceneTexWidth, sceneTexHeight, 0); - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glPopAttrib(); -} - -void Renderer::drawSceneTexture() -{ - if (sceneTexture == 0) - return; - glBindTexture(GL_TEXTURE_2D, sceneTexture); - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, 0.0f, 1.0f); - glEnd(); -} - -void Renderer::drawBlendedVertices(float xdelta, float ydelta, float blend) -{ - glColor4f(1.0f, 1.0f, 1.0f, blend); - glTexCoord2i(0, 0); glVertex2f(xdelta, ydelta); - glTexCoord2i(1, 0); glVertex2f(sceneTexWScale+xdelta, ydelta); - glTexCoord2i(1, 1); glVertex2f(sceneTexWScale+xdelta, sceneTexHScale+ydelta); - glTexCoord2i(0, 1); glVertex2f(xdelta, sceneTexHScale+ydelta); -} - -void Renderer::drawGaussian3x3(float xdelta, float ydelta, GLsizei width, GLsizei height, float blend) -{ -#ifdef USE_BLOOM_LISTS - if (gaussianLists[0] == 0) - { - gaussianLists[0] = glGenLists(1); - glNewList(gaussianLists[0], GL_COMPILE); -#endif - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, 0.0f, blend); - drawBlendedVertices(-xdelta, 0.0f, 0.25f*blend); - drawBlendedVertices( xdelta, 0.0f, 0.20f*blend); - glEnd(); - - // Take result of horiz pass and apply vertical pass - glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, - width, height, 0); - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, -ydelta, 0.429f); - drawBlendedVertices(0.0f, ydelta, 0.300f); - glEnd(); -#ifdef USE_BLOOM_LISTS - glEndList(); - } - glCallList(gaussianLists[0]); -#endif -} - -void Renderer::drawGaussian5x5(float xdelta, float ydelta, GLsizei width, GLsizei height, float blend) -{ -#ifdef USE_BLOOM_LISTS - if (gaussianLists[1] == 0) - { - gaussianLists[1] = glGenLists(1); - glNewList(gaussianLists[1], GL_COMPILE); -#endif - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, 0.0f, blend); - drawBlendedVertices(-xdelta, 0.0f, 0.475f*blend); - drawBlendedVertices( xdelta, 0.0f, 0.475f*blend); - drawBlendedVertices(-2.0f*xdelta, 0.0f, 0.075f*blend); - drawBlendedVertices( 2.0f*xdelta, 0.0f, 0.075f*blend); - glEnd(); - glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, - width, height, 0); - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, -ydelta, 0.475f); - drawBlendedVertices(0.0f, ydelta, 0.475f); - drawBlendedVertices(0.0f, -2.0f*ydelta, 0.075f); - drawBlendedVertices(0.0f, 2.0f*ydelta, 0.075f); - glEnd(); -#ifdef USE_BLOOM_LISTS - glEndList(); - } - glCallList(gaussianLists[1]); -#endif -} - -void Renderer::drawGaussian9x9(float xdelta, float ydelta, GLsizei width, GLsizei height, float blend) -{ -#ifdef USE_BLOOM_LISTS - if (gaussianLists[2] == 0) - { - gaussianLists[2] = glGenLists(1); - glNewList(gaussianLists[2], GL_COMPILE); -#endif - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, 0.0f, blend); - drawBlendedVertices(-xdelta, 0.0f, 0.632f*blend); - drawBlendedVertices( xdelta, 0.0f, 0.632f*blend); - drawBlendedVertices(-2.0f*xdelta, 0.0f, 0.159f*blend); - drawBlendedVertices( 2.0f*xdelta, 0.0f, 0.159f*blend); - drawBlendedVertices(-3.0f*xdelta, 0.0f, 0.016f*blend); - drawBlendedVertices( 3.0f*xdelta, 0.0f, 0.016f*blend); - glEnd(); - - glCopyTexImage2D(GL_TEXTURE_2D, 0, blurFormat, 0, 0, - width, height, 0); - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, -ydelta, 0.632f); - drawBlendedVertices(0.0f, ydelta, 0.632f); - drawBlendedVertices(0.0f, -2.0f*ydelta, 0.159f); - drawBlendedVertices(0.0f, 2.0f*ydelta, 0.159f); - drawBlendedVertices(0.0f, -3.0f*ydelta, 0.016f); - drawBlendedVertices(0.0f, 3.0f*ydelta, 0.016f); - glEnd(); -#ifdef USE_BLOOM_LISTS - glEndList(); - } - glCallList(gaussianLists[2]); -#endif -} - -void Renderer::drawBlur() -{ - blurTextures[0]->bind(); - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, 0.0f, 1.0f); - glEnd(); - blurTextures[1]->bind(); - glBegin(GL_QUADS); - drawBlendedVertices(0.0f, 0.0f, 1.0f); - glEnd(); -} - -bool Renderer::getBloomEnabled() -{ - return bloomEnabled; -} - -void Renderer::setBloomEnabled(bool aBloomEnabled) -{ - bloomEnabled = aBloomEnabled; -} - -void Renderer::increaseBrightness() -{ - brightPlus += 1.0f; -} - -void Renderer::decreaseBrightness() -{ - brightPlus -= 1.0f; -} - -float Renderer::getBrightness() -{ - return brightPlus; -} -#endif // USE_HDR - void Renderer::render(const Observer& observer, const Universe& universe, float faintestMagNight, @@ -2492,9 +1851,7 @@ void Renderer::draw(const Observer& observer, m_cameraOrientation = observer.getOrientationf(); // Get the view frustum used for culling in camera space. - Frustum frustum(degToRad(fov), - getAspectRatio(), - MinNearPlaneDistance); + Frustum frustum(degToRad(fov), getAspectRatio(), MinNearPlaneDistance); // Get the transformed frustum, used for culling in the astrocentric coordinate // system. @@ -2728,7 +2085,7 @@ void Renderer::draw(const Observer& observer, // atmosphere. If so, we need to adjust the sky color as well as the // limiting magnitude of stars (so stars aren't visible in the daytime // on planets with thick atmospheres.) - if (renderFlags & ShowAtmospheres) + if ((renderFlags & ShowAtmospheres) != 0) { for (const auto& render_item : renderList) { @@ -3585,7 +2942,8 @@ void Renderer::renderObjectAsPoint(const Vector3f& position, bool useHalos, bool emissive) { - float maxDiscSize = (starStyle == ScaledDiscStars) ? MaxScaledDiscStarSize : 1.0f; + const float maxSize = MaxScaledDiscStarSize; + float maxDiscSize = (starStyle == ScaledDiscStars) ? maxSize : 1.0f; float maxBlendDiscSize = maxDiscSize + 3.0f; bool useScaledDiscs = starStyle == ScaledDiscStars; @@ -3622,15 +2980,12 @@ void Renderer::renderObjectAsPoint(const Vector3f& position, { if (alpha > 1.0f) { - float discScale = min(MaxScaledDiscStarSize, (float) pow(2.0f, 0.3f * (satPoint - appMag))); + float discScale = min(maxSize, (float) pow(2.0f, 0.3f * (satPoint - appMag))); pointSize *= max(1.0f, discScale); glareAlpha = min(0.5f, discScale / 4.0f); - if (discSizeInPixels > MaxScaledDiscStarSize) - { - glareAlpha = min(glareAlpha, - (MaxScaledDiscStarSize - discSizeInPixels) / MaxScaledDiscStarSize + 1.0f); - } + if (discSizeInPixels > maxSize) + glareAlpha = min(glareAlpha, (maxSize - discSizeInPixels) / maxSize + 1.0f); glareSize = pointSize * 3.0f; alpha = 1.0f; @@ -4739,9 +4094,7 @@ void Renderer::renderObject(const Vector3f& pos, { Texture* ringsTex = obj.rings->texture.find(textureResolution); if (ringsTex != nullptr) - { ringsTex->bind(); - } } if (distance > obj.rings->innerRadius) @@ -4998,7 +4351,7 @@ void Renderer::renderPlanet(Body& body, // Add ring shadow records for each light - if (body.getRings() && + if (body.getRings() != nullptr && (renderFlags & ShowPlanetRings) != 0 && (renderFlags & ShowRingShadows) != 0) { @@ -5076,10 +4429,9 @@ void Renderer::renderPlanet(Body& body, // that exotic cases with shadows from two ring different ring systems aren't handled. for (unsigned int li = 0; li < lights.nLights; li++) { - if (lights.ringShadows[li].ringSystem != nullptr) + RingSystem* rings = lights.ringShadows[li].ringSystem; + if (rings != nullptr) { - RingSystem* rings = lights.ringShadows[li].ringSystem; - // Use the first set of ring shadows found (shadowing the brightest light // source.) if (lights.shadowingRingSystem == nullptr) @@ -5096,7 +4448,7 @@ void Renderer::renderPlanet(Body& body, float projectedRingSize = std::abs(lights.lights[li].direction_obj.dot(lights.ringPlaneNormal)) * ringWidth; float projectedRingSizeInPixels = projectedRingSize / (max(nearPlaneDistance, altitude) * pixelSize); Texture* ringsTex = rings->texture.find(textureResolution); - if (ringsTex) + if (ringsTex != nullptr) { // Calculate the approximate distance from the shadowed object to the rings Hyperplane ringPlane(lights.ringPlaneNormal, lights.ringCenter); @@ -5143,16 +4495,9 @@ void Renderer::renderPlanet(Body& body, // us explicitly set the LOD. But, they do all have an optional lodBias parameter // for the textureXD instruction. The bias is just the difference between the // area light LOD and the approximate GPU calculated LOD. - float lodBias = max(0.0f, lod - gpuLod); - - if (GLEW_ARB_shader_texture_lod) - { - lights.ringShadows[li].texLod = lod; - } - else - { - lights.ringShadows[li].texLod = lodBias; - } + if (!GLEW_ARB_shader_texture_lod) + lod = max(0.0f, lod - gpuLod); + lights.ringShadows[li].texLod = lod; } else { @@ -5324,7 +4669,6 @@ static float cometDustTailLength(float distanceToSun, } -// TODO: Remove unused parameters?? void Renderer::renderCometTail(const Body& body, const Vector3f& pos, const Observer& observer, @@ -5500,7 +4844,7 @@ void Renderer::renderCometTail(const Body& body, glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_NORMAL_ARRAY); - if (brightness == -1) + if (brightness != -1) glDisableVertexAttribArray(brightness); glEnable(GL_CULL_FACE); glUseProgram(0); @@ -5617,7 +4961,7 @@ static float luminosityAtOpposition(float sunLuminosity, static bool isBodyVisible(const Body* body, int bodyVisibilityMask) { int klass = body->getClassification(); - switch (body->getClassification()) + switch (klass) { // Diffuse objects don't have controls to show/hide visibility case Body::Diffuse: @@ -6211,278 +5555,6 @@ void Renderer::addStarOrbitToRenderList(const Star& star, } -template class ObjectRenderer : public OctreeProcessor -{ - public: - ObjectRenderer(PREC _distanceLimit); - - void process(const OBJ& /*unused*/, PREC /*unused*/, float /*unused*/) {}; - - public: - const Observer* observer{ nullptr }; - -#ifdef USE_GLCONTEXT - GLContext* context{ nullptr }; -#endif - Renderer* renderer{ nullptr }; - - Eigen::Vector3f viewNormal; - - float fov{ 0.0f }; - float size{ 0.0f }; - float pixelSize{ 0.0f }; - float faintestMag{ 0.0f }; - float faintestMagNight{ 0.0f }; - float saturationMag{ 0.0f }; -#ifdef USE_HDR - float exposure{ 0.0f }; -#endif - float brightnessScale{ 0.0f }; - float brightnessBias{ 0.0f }; - float distanceLimit{ 0.0f }; - - // Objects brighter than labelThresholdMag will be labeled - float labelThresholdMag{ 0.0f }; - - // These are not fully used by this template's descendants - // but we place them here just in case a more sophisticated - // rendering scheme is implemented: - int nRendered{ 0 }; - int nClose{ 0 }; - int nBright{ 0 }; - int nProcessed{ 0 }; - int nLabelled{ 0 }; - - uint64_t renderFlags{ 0 }; - int labelMode{ 0 }; -}; - - -template -ObjectRenderer::ObjectRenderer(const PREC _distanceLimit) : - distanceLimit((float) _distanceLimit) -{ -} - - -class PointStarRenderer : public ObjectRenderer -{ - public: - PointStarRenderer(); - - void process(const Star& star, float distance, float appMag); - - public: - Vector3d obsPos; - - vector* renderList{ nullptr }; - PointStarVertexBuffer* starVertexBuffer{ nullptr }; - PointStarVertexBuffer* glareVertexBuffer{ nullptr }; - - const StarDatabase* starDB{ nullptr }; - - bool useScaledDiscs{ false }; - float maxDiscSize{ 1.0f }; - - float cosFOV{ 1.0f }; - - const ColorTemperatureTable* colorTemp{ nullptr }; - float SolarSystemMaxDistance { 1.0f }; -#ifdef DEBUG_HDR_ADAPT - float minMag; - float maxMag; - float minAlpha; - float maxAlpha; - float maxSize; - float above; - unsigned long countAboveN; - unsigned long total; -#endif -}; - - -PointStarRenderer::PointStarRenderer() : - ObjectRenderer(STAR_DISTANCE_LIMIT) -{ -} - - -void PointStarRenderer::process(const Star& star, float distance, float appMag) -{ - nProcessed++; - - Vector3f starPos = star.getPosition(); - - // Calculate the difference at double precision *before* converting to float. - // This is very important for stars that are far from the origin. - Vector3f relPos = (starPos.cast() - obsPos).cast(); - float orbitalRadius = star.getOrbitalRadius(); - bool hasOrbit = orbitalRadius > 0.0f; - - if (distance > distanceLimit) - return; - - - // A very rough check to see if the star may be visible: is the star in - // front of the viewer? If the star might be close (relPos.x^2 < 0.1) or - // is moving in an orbit, we'll always regard it as potentially visible. - // TODO: consider normalizing relPos and comparing relPos*viewNormal against - // cosFOV--this will cull many more stars than relPos*viewNormal, at the - // cost of a normalize per star. - if (relPos.dot(viewNormal) > 0.0f || relPos.x() * relPos.x() < 0.1f || hasOrbit) - { -#ifdef HDR_COMPRESS - Color starColorFull = colorTemp->lookupColor(star.getTemperature()); - Color starColor(starColorFull.red() * 0.5f, - starColorFull.green() * 0.5f, - starColorFull.blue() * 0.5f); -#else - Color starColor = colorTemp->lookupColor(star.getTemperature()); -#endif - float discSizeInPixels = 0.0f; - float orbitSizeInPixels = 0.0f; - - if (hasOrbit) - orbitSizeInPixels = orbitalRadius / (distance * pixelSize); - - // Special handling for stars less than one light year away . . . - // We can't just go ahead and render a nearby star in the usual way - // for two reasons: - // * It may be clipped by the near plane - // * It may be large enough that we should render it as a mesh - // instead of a particle - // It's possible that the second condition might apply for stars - // further than one light year away if the star is huge, the fov is - // very small and the resolution is high. We'll ignore this for now - // and use the most inexpensive test possible . . . - if (distance < 1.0f || orbitSizeInPixels > 1.0f) - { - // Compute the position of the observer relative to the star. - // This is a much more accurate (and expensive) distance - // calculation than the previous one which used the observer's - // position rounded off to floats. - Vector3d hPos = astrocentricPosition(observer->getPosition(), - star, - observer->getTime()); - relPos = hPos.cast() * -astro::kilometersToLightYears(1.0f); - distance = relPos.norm(); - - // Recompute apparent magnitude using new distance computation - appMag = astro::absToAppMag(star.getAbsoluteMagnitude(), distance); - - starPos = obsPos.cast() + relPos * (RenderDistance / distance); - - float radius = star.getRadius(); - discSizeInPixels = radius / astro::lightYearsToKilometers(distance) / pixelSize; - ++nClose; - } - - // Place labels for stars brighter than the specified label threshold brightness - if ((labelMode & Renderer::StarLabels) && appMag < labelThresholdMag) - { - Vector3f starDir = relPos; - starDir.normalize(); - if (starDir.dot(viewNormal) > cosFOV) - { - float distr = 3.5f * (labelThresholdMag - appMag)/labelThresholdMag; - if (distr > 1.0f) - distr = 1.0f; - renderer->addBackgroundAnnotation(nullptr, starDB->getStarName(star, true), - Color(Renderer::StarLabelColor, distr * Renderer::StarLabelColor.alpha()), - relPos); - nLabelled++; - } - } - - // Stars closer than the maximum solar system size are actually - // added to the render list and depth sorted, since they may occlude - // planets. - if (distance > SolarSystemMaxDistance) - { -#ifdef USE_HDR - float satPoint = saturationMag; - float alpha = exposure*(faintestMag - appMag)/(faintestMag - saturationMag + 0.001f); -#else - float satPoint = faintestMag - (1.0f - brightnessBias) / brightnessScale; // TODO: precompute this value - float alpha = (faintestMag - appMag) * brightnessScale + brightnessBias; -#endif -#ifdef DEBUG_HDR_ADAPT - minMag = max(minMag, appMag); - maxMag = min(maxMag, appMag); - minAlpha = min(minAlpha, alpha); - maxAlpha = max(maxAlpha, alpha); - ++total; - if (alpha > above) - { - ++countAboveN; - } -#endif - - if (useScaledDiscs) - { - float discSize = size; - if (alpha < 0.0f) - { - alpha = 0.0f; - } - else if (alpha > 1.0f) - { - float discScale = min(MaxScaledDiscStarSize, (float) pow(2.0f, 0.3f * (satPoint - appMag))); - discSize *= discScale; - - float glareAlpha = min(0.5f, discScale / 4.0f); - glareVertexBuffer->addStar(relPos, Color(starColor, glareAlpha), discSize * 3.0f); - - alpha = 1.0f; - } - starVertexBuffer->addStar(relPos, Color(starColor, alpha), discSize); - } - else - { - if (alpha < 0.0f) - { - alpha = 0.0f; - } - else if (alpha > 1.0f) - { - float discScale = min(100.0f, satPoint - appMag + 2.0f); - float glareAlpha = min(GlareOpacity, (discScale - 2.0f) / 4.0f); - glareVertexBuffer->addStar(relPos, Color(starColor, glareAlpha), 2.0f * discScale * size); -#ifdef DEBUG_HDR_ADAPT - maxSize = max(maxSize, 2.0f * discScale * size); -#endif - } - starVertexBuffer->addStar(relPos, Color(starColor, alpha), size); - } - - ++nRendered; - } - else - { - Matrix3f viewMat = observer->getOrientationf().toRotationMatrix(); - Vector3f viewMatZ = viewMat.row(2); - - RenderListEntry rle; - rle.renderableType = RenderListEntry::RenderableStar; - rle.star = ☆ - - // Objects in the render list are always rendered relative to - // a viewer at the origin--this is different than for distant - // stars. - float scale = astro::lightYearsToKilometers(1.0f); - rle.position = relPos * scale; - rle.centerZ = rle.position.dot(viewMatZ); - rle.distance = rle.position.norm(); - rle.radius = star.getRadius(); - rle.discSizeInPixels = discSizeInPixels; - rle.appMag = appMag; - rle.isOpaque = true; - renderList->push_back(rle); - } - } -} - - // Calculate the maximum field of view (from top left corner to bottom right) of // a frustum with the specified aspect ratio (width/height) and vertical field of // view. We follow the convention used elsewhere and use units of degrees for diff --git a/src/celengine/render.h b/src/celengine/render.h index 41464341..d592aa8c 100644 --- a/src/celengine/render.h +++ b/src/celengine/render.h @@ -11,6 +11,9 @@ #ifndef _CELENGINE_RENDER_H_ #define _CELENGINE_RENDER_H_ +#include +#include +#include #include #include #include @@ -21,15 +24,13 @@ #endif #include #include -#include "celengine/vertexobject.h" +#include +#include #if NO_TTF #include #else #include #endif -#include -#include -#include class RendererWatcher; @@ -38,6 +39,7 @@ class ReferenceMark; class CurvePlot; class AsterismList; class Rect; +class PointStarVertexBuffer; struct LightSource { @@ -48,39 +50,6 @@ struct LightSource }; -struct RenderListEntry -{ - EIGEN_MAKE_ALIGNED_OPERATOR_NEW - - enum RenderableType - { - RenderableStar, - RenderableBody, - RenderableCometTail, - RenderableReferenceMark, - }; - - union - { - const Star* star; - Body* body; - const ReferenceMark* refMark; - }; - - Eigen::Vector3f position; - Eigen::Vector3f sun; - float distance; - float radius; - float centerZ; - float nearZ; - float farZ; - float discSizeInPixels; - float appMag; - RenderableType renderableType; - bool isOpaque; -}; - - struct SecondaryIlluminator { const Body* body; @@ -90,8 +59,6 @@ struct SecondaryIlluminator }; -class PointStarVertexBuffer; - class Renderer { public: diff --git a/src/celengine/renderlistentry.h b/src/celengine/renderlistentry.h new file mode 100644 index 00000000..c677ba43 --- /dev/null +++ b/src/celengine/renderlistentry.h @@ -0,0 +1,49 @@ +// renderlistentry.h +// +// Copyright (C) 2001-2019, Celestia Development Team +// Contact: Chris Laurel +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License +// as published by the Free Software Foundation; either version 2 +// of the License, or (at your option) any later version. + +#pragma once + +#include + +class Star; +class Body; +class ReferenceMark; + +struct RenderListEntry +{ + EIGEN_MAKE_ALIGNED_OPERATOR_NEW + + enum RenderableType + { + RenderableStar, + RenderableBody, + RenderableCometTail, + RenderableReferenceMark, + }; + + union + { + const Star* star; + Body* body; + const ReferenceMark* refMark; + }; + + Eigen::Vector3f position; + Eigen::Vector3f sun; + float distance; + float radius; + float centerZ; + float nearZ; + float farZ; + float discSizeInPixels; + float appMag; + RenderableType renderableType; + bool isOpaque; +};