Refactor render.cpp and extract some classes to own files

pull/3/head
Hleb Valoshka 2019-12-01 15:32:10 +03:00
parent 7f052a65e4
commit 8778c07ccb
12 changed files with 1116 additions and 988 deletions

View File

@ -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

View File

@ -27,6 +27,8 @@
// License and a copy of the GNU General Public License along with
// orbitpath. If not, see <http://www.gnu.org/licenses/>.
#pragma once
#include <deque>
#include <Eigen/Geometry>

View File

@ -0,0 +1,443 @@
// render.cpp
//
// Copyright (C) 2001-2009, the Celestia Development Team
// Original version by Chris Laurel <claurel@gmail.com>
//
// 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

View File

@ -0,0 +1,63 @@
// objectrenderer.h
//
// Copyright (C) 2001-2019, the Celestia Development Team
// Original version by Chris Laurel <claurel@gmail.com>
//
// 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 <Eigen/Core>
#include "octree.h"
#ifdef USE_GLCONTEXT
class GLContext;
#endif
class Observer;
class Renderer;
template <class OBJ, class PREC> class ObjectRenderer : public OctreeProcessor<OBJ, PREC>
{
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 };
};

View File

@ -0,0 +1,48 @@
// orbitsampler.h
//
// Copyright (C) 2001-2019, the Celestia Development Team
// Original version by Chris Laurel <claurel@gmail.com>
//
// 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 <Eigen/Core>
#include <celephem/orbit.h>
#include "curveplot.h"
class OrbitSampler : public OrbitSampleProc
{
public:
std::vector<CurvePlotSample> 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);
}
}
};

View File

@ -0,0 +1,203 @@
// pointstarrenderer.cpp
//
// Copyright (C) 2001-2019, the Celestia Development Team
// Original version by Chris Laurel <claurel@gmail.com>
//
// 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 <celengine/starcolors.h>
#include <celengine/star.h>
#include <celengine/univcoord.h>
#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<Star, float>(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<double>() - obsPos).cast<float>();
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<float>() * -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 = &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);
}
}
}

View File

@ -0,0 +1,65 @@
// pointstarrenderer.h
//
// Copyright (C) 2001-2019, the Celestia Development Team
// Original version by Chris Laurel <claurel@gmail.com>
//
// 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 <Eigen/Core>
#include <vector>
#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<Star, float>
{
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<RenderListEntry>* 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 };
};

View File

@ -0,0 +1,133 @@
// starfield.cpp
//
// Copyright (C) 2001-2019, the Celestia Development Team
// Original version by Chris Laurel <claurel@gmail.com>
//
// 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 <GL/glew.h>
#include <celutil/color.h>
#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;
}

View File

@ -0,0 +1,75 @@
// pointstarvertexbuffer.h
//
// Copyright (C) 2001-2019, the Celestia Development Team
// Original version by Chris Laurel <claurel@gmail.com>
//
// 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 <Eigen/Core>
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;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -11,6 +11,9 @@
#ifndef _CELENGINE_RENDER_H_
#define _CELENGINE_RENDER_H_
#include <vector>
#include <list>
#include <string>
#include <Eigen/Core>
#include <celmath/frustum.h>
#include <celengine/universe.h>
@ -21,15 +24,13 @@
#endif
#include <celengine/starcolors.h>
#include <celengine/rendcontext.h>
#include "celengine/vertexobject.h"
#include <celengine/renderlistentry.h>
#include <celengine/vertexobject.h>
#if NO_TTF
#include <celtxf/texturefont.h>
#else
#include <celttf/truetypefont.h>
#endif
#include <vector>
#include <list>
#include <string>
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:

View File

@ -0,0 +1,49 @@
// renderlistentry.h
//
// Copyright (C) 2001-2019, Celestia Development Team
// Contact: Chris Laurel <claurel@gmail.com>
//
// 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 <Eigen/Core>
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;
};