Big common application code refactoring

* Allow to parse four element vectors
 * Allow colors defined in HTML notation (#rrggbbaa)
   in CEL scripts
 * Refactor Overlay::Rectangle to an independent class
 * Refactor CelestiaCore::OverlayImage to an independent class
 * Refactor CelestiaCore::View to an independent class
 * Rename Renderer::getScreenSize to getViewport
 * Add wrappers for scissors test and MSAA control
pull/444/head
Hleb Valoshka 2019-10-08 23:00:19 +03:00
parent 6e44de22f1
commit e3baaad767
27 changed files with 1067 additions and 669 deletions

View File

@ -74,6 +74,8 @@ set(CELENGINE_SOURCES
opencluster.h
overlay.cpp
overlay.h
overlayimage.cpp
overlayimage.h
parseobject.cpp
parseobject.h
parser.cpp
@ -84,6 +86,7 @@ set(CELENGINE_SOURCES
# particlesystem.h
planetgrid.cpp
planetgrid.h
rectangle.h
referencemark.h
rendcontext.cpp
rendcontext.h

View File

@ -228,6 +228,24 @@ int Console::getHeight() const
}
void Console::setColor(float r, float g, float b, float a) const
{
glColor4f(r, g, b, a);
}
void Console::setColor(const Color& c) const
{
glColor4f(c.red(), c.green(), c.blue(), c.alpha());
}
void Console::moveBy(float dx, float dy, float dz) const
{
glTranslatef(dx, dy, dz);
}
//
// ConsoleStreamBuf implementation
//

View File

@ -56,6 +56,11 @@ class Console : public std::ostream
void setScale(int, int);
void setFont(TextureFont*);
void setColor(float r, float g, float b, float a) const;
void setColor(const Color& c) const;
void moveBy(float dx, float dy, float dz = 0.0f) const;
void print(wchar_t);
void print(char*);
void newline();

View File

@ -15,7 +15,9 @@
#include <celutil/debug.h>
#include "vecgl.h"
#include "overlay.h"
#include "rectangle.h"
#include "render.h"
#include "texture.h"
using namespace std;
using namespace Eigen;
@ -166,101 +168,31 @@ void Overlay::print(const char* s)
}
}
static void drawRect(const Renderer& r,
const array<float, 8>& vertices,
const vector<Vector4f>& colors,
Overlay::RectType type,
float linewidth)
void Overlay::drawRectangle(const Rect& r)
{
uint32_t p = 0;
switch (type)
{
case Overlay::RectType::Textured:
p |= ShaderProperties::HasTexture;
// [[ fallthrough ]]
case Overlay::RectType::Outlined:
case Overlay::RectType::Filled:
switch (colors.size())
{
case 0:
break;
case 1:
p |= ShaderProperties::UniformColor;
break;
case 4:
p |= ShaderProperties::PerVertexColor;
break;
default:
fmt::fprintf(cerr, "Incorrect number of colors: %i\n", colors.size());
break;
}
default:
break;
}
auto prog = r.getShaderManager().getShader(ShaderProperties(p));
if (prog == nullptr)
return;
constexpr array<short, 8> texels = {0, 1, 1, 1, 1, 0, 0, 0};
auto s = static_cast<GLsizeiptr>(memsize(vertices) + memsize(texels) + 4*4*sizeof(GLfloat));
static celgl::VertexObject vo{ GL_ARRAY_BUFFER, s, GL_DYNAMIC_DRAW };
vo.bindWritable();
if (!vo.initialized())
{
vo.allocate();
vo.setBufferData(texels.data(), memsize(vertices), memsize(texels));
vo.setVertices(2, GL_FLOAT);
vo.setTextureCoords(2, GL_SHORT, false, 0, memsize(vertices));
vo.setColors(4, GL_FLOAT, false, 0, memsize(vertices) + memsize(texels));
}
vo.setBufferData(vertices.data(), 0, memsize(vertices));
if (colors.size() == 4)
vo.setBufferData(colors.data(), memsize(vertices) + memsize(texels), 4*4*sizeof(GLfloat));
prog->use();
if (type == Overlay::RectType::Textured)
prog->samplerParam("tex") = 0;
if (colors.size() == 1)
prog->vec4Param("color") = colors[0];
if (type != Overlay::RectType::Outlined)
{
vo.draw(GL_TRIANGLE_FAN, 4);
}
else
{
if (linewidth != 1.0f)
glLineWidth(linewidth);
vo.draw(GL_LINE_LOOP, 4);
if (linewidth != 1.0f)
glLineWidth(1.0f);
}
glUseProgram(0);
vo.unbind();
}
void Overlay::rect(const Overlay::Rectangle& r)
{
if (useTexture && r.type != Overlay::RectType::Textured)
if (useTexture && r.tex == nullptr)
{
glDisable(GL_TEXTURE_2D);
useTexture = false;
}
vector<Vector4f> cv;
for (const Color& c : r.colors)
cv.push_back(c.toVector4());
array<float, 8> coord = { r.x, r.y, r.x+r.w, r.y, r.x+r.w, r.y+r.h, r.x, r.y+r.h };
drawRect(renderer, coord, cv, r.type, r.lw);
renderer.drawRectangle(r);
}
void Overlay::setColor(float r, float g, float b, float a) const
{
glColor4f(r, g, b, a);
}
void Overlay::setColor(const Color& c) const
{
glColor4f(c.red(), c.green(), c.blue(), c.alpha());
}
void Overlay::moveBy(float dx, float dy, float dz) const
{
glTranslatef(dx, dy, dz);
}
//
// OverlayStreamBuf implementation

View File

@ -10,15 +10,17 @@
#ifndef _OVERLAY_H_
#define _OVERLAY_H_
#include <string>
#include <algorithm>
#include <array>
#include <iostream>
#include <vector>
#include <celtxf/texturefont.h>
#include <string>
#include <celutil/color.h>
#include <celtxf/texturefont.h>
class Overlay;
class Renderer;
class Rect;
// Custom streambuf class to support C++ operator style output. The
// output is completely unbuffered so that it can coexist with printf
@ -60,32 +62,24 @@ class Overlay : public std::ostream
void setWindowSize(int, int);
void setFont(TextureFont*);
enum class RectType
void setColor(float r, float g, float b, float a) const;
void setColor(const Color& c) const;
void moveBy(float dx, float dy, float dz = 0.0f) const;
void savePos() const
{
Outlined = 0x0001,
Filled = 0x0002,
Textured = 0x0004
glPushMatrix();
};
void restorePos() const
{
glPopMatrix();
};
const Renderer& getRenderer() const
{
return renderer;
};
struct Rectangle
{
Rectangle() = default;
Rectangle(float _x, float _y, float _w, float _h, const Color& _c, RectType _t, float _lw = 1.0f) :
x(_x), y(_y), w(_w), h(_h), type(_t), lw(_lw)
{
colors.push_back(_c);
};
Rectangle(float _x, float _y, float _w, float _h, const std::vector<Color>& _c, RectType _t, float _lw = 1.0f) :
x(_x), y(_y), w(_w), h(_h), colors(_c), type(_t), lw(_lw)
{
};
float x, y, w, h;
float lw { 1.0f };
RectType type { RectType::Filled };
std::vector<Color> colors;
};
void rect(const Rectangle&);
void drawRectangle(const Rect&);
void beginText();
void endText();

View File

@ -0,0 +1,65 @@
#include <algorithm>
#include <iostream>
#include <celmath/mathlib.h>
#include "overlayimage.h"
#include "rectangle.h"
#include "render.h"
using namespace celmath;
OverlayImage::OverlayImage(fs::path f, Renderer *r) :
filename(std::move(f)),
renderer(r)
{
texture = std::unique_ptr<Texture>(LoadTextureFromFile(fs::path("images") / filename));
}
void OverlayImage::setColor(const Color& c)
{
colors.fill(c);
}
void OverlayImage::setColor(std::array<Color, 4>& c)
{
std::copy(c.begin(), c.end(), colors.begin());
}
void OverlayImage::render(float curr_time, int width, int height)
{
if (renderer == nullptr || texture == nullptr || (curr_time >= start + duration))
return;
float xSize = texture->getWidth();
float ySize = texture->getHeight();
// center overlay image horizontally if offsetX = 0
float left = (width * (1 + offsetX) - xSize)/2;
// center overlay image vertically if offsetY = 0
float bottom = (height * (1 + offsetY) - ySize)/2;
if (fitscreen)
{
float coeffx = xSize / width; // overlay pict width/view window width ratio
float coeffy = ySize / height; // overlay pict height/view window height ratio
xSize /= coeffx; // new overlay picture width size to fit viewport
ySize /= coeffy; // new overlay picture height to fit viewport
left = (width - xSize) / 2; // to be sure overlay pict is centered in viewport
bottom = 0; // overlay pict locked at bottom of screen
}
float alpha = 1.0f;
if (curr_time > start + fadeafter)
{
alpha = clamp(start + duration - curr_time);
}
Rect r(left, bottom, xSize, ySize);
r.tex = texture.get();
for (size_t i = 0; i < colors.size(); i++)
{
r.colors[i] = Color(colors[i], colors[i].alpha() * alpha);
}
r.nColors = 4;
renderer->drawRectangle(r);
}

View File

@ -0,0 +1,60 @@
#pragma once
#include <array>
#include <memory>
#include <celcompat/filesystem.h>
#include "texture.h"
class Renderer;
class OverlayImage
{
public:
OverlayImage(fs::path, Renderer*);
OverlayImage() = delete;
~OverlayImage() = default;
OverlayImage(OverlayImage&) = delete;
OverlayImage(OverlayImage&&) = delete;
void render(float, int, int);
bool isNewImage(const fs::path& f) const
{
return filename != f;
}
void setStartTime(float t)
{
start = t;
}
void setDuration(float t)
{
duration = t;
}
void setFadeAfter(float t)
{
fadeafter = t;
}
void setOffset(float x, float y)
{
offsetX = x;
offsetY = y;
}
void fitScreen(bool t)
{
fitscreen = t;
}
void setColor(const Color& c);
void setColor(std::array<Color, 4>& c);
private:
float start { 0.0f };
float duration { 0.0f };
float fadeafter { 0.0f };
float offsetX { 0.0f };
float offsetY { 0.0f };
bool fitscreen { false };
std::array<Color, 4> colors;
fs::path filename;
std::unique_ptr<Texture> texture;
Renderer *renderer { nullptr };
};

View File

@ -442,6 +442,44 @@ bool AssociativeArray::getVector(const string& key, Vector3f& val) const
}
bool AssociativeArray::getVector(const string& key, Vector4d& val) const
{
Value* v = getValue(key);
if (v == nullptr || v->getType() != Value::ArrayType)
return false;
ValueArray* arr = v->getArray();
if (arr->size() != 4)
return false;
Value* x = (*arr)[0];
Value* y = (*arr)[1];
Value* z = (*arr)[2];
Value* w = (*arr)[3];
if (x->getType() != Value::NumberType ||
y->getType() != Value::NumberType ||
z->getType() != Value::NumberType ||
w->getType() != Value::NumberType)
return false;
val = Vector4d(x->getNumber(), y->getNumber(), z->getNumber(), w->getNumber());
return true;
}
bool AssociativeArray::getVector(const string& key, Vector4f& val) const
{
Vector4d vecVal;
if (!getVector(key, vecVal))
return false;
val = vecVal.cast<float>();
return true;
}
/**
* Retrieves a quaternion, scaled to an associated angle unit.
*
@ -490,14 +528,40 @@ bool AssociativeArray::getRotation(const string& key, Eigen::Quaternionf& val) c
bool AssociativeArray::getColor(const string& key, Color& val) const
{
Vector3d vecVal;
Vector4d vec4;
if (getVector(key, vec4))
{
Vector4f vec4f = vec4.cast<float>();
val = Color(vec4f);
return true;
}
if (!getVector(key, vecVal))
return false;
Vector3d vec3;
if (getVector(key, vec3))
{
Vector3f vec3f = vec3.cast<float>();
val = Color(vec3f);
return true;
}
val = Color((float) vecVal.x(), (float) vecVal.y(), (float) vecVal.z());
string rgba;
if (getString(key, rgba))
{
int r, g, b, a;
int ret = sscanf(rgba.c_str(), "#%2x%2x%2x%2x", &r, &g, &b, &a);
switch (ret)
{
case 3:
a = 0xFF;
case 4:
val = Color((char unsigned)r, (char unsigned)g, (unsigned char)b, (unsigned char)a);
return true;
default:
return false;
}
}
return true;
return false;
}

View File

@ -42,6 +42,8 @@ class AssociativeArray
bool getBoolean(const std::string&, bool&) const;
bool getVector(const std::string&, Eigen::Vector3d&) const;
bool getVector(const std::string&, Eigen::Vector3f&) const;
bool getVector(const std::string&, Eigen::Vector4d&) const;
bool getVector(const std::string&, Eigen::Vector4f&) const;
bool getRotation(const std::string&, Eigen::Quaternionf&) const;
bool getColor(const std::string&, Color&) const;
bool getAngle(const std::string&, double&, double = 1.0, double = 0.0) const;

View File

@ -0,0 +1,61 @@
// rectangle.h
//
// Copyright (C) 2019, Celestia Development Team
//
// 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 <algorithm>
#include <array>
#include <celutil/color.h>
class Renderer;
class Texture;
class Rect
{
public:
enum class Type
{
BorderOnly = 0x0001,
Filled = 0x0002,
};
Rect() = default;
Rect(float _x, float _y, float _w, float _h) :
x(_x), y(_y), w(_w), h(_h)
{
};
void setColor(const Color &_color)
{
color = _color;
nColors = 1;
}
void setColor(const std::array<Color,4> _colors)
{
std::copy(_colors.begin(), _colors.end(), colors.begin());
nColors = 4;
}
void setLineWidth(float _lw)
{
lw = _lw;
}
void setType(Type _type)
{
type = _type;
}
float x, y, w, h;
float lw { 1.0f };
union
{
std::array<Color,4> colors;
Color color;
};
Texture *tex { nullptr };
Type type { Type::Filled };
int nColors { 0 };
};

View File

@ -58,6 +58,7 @@ std::ofstream hdrlog;
#include "modelgeometry.h"
#include "curveplot.h"
#include "shadermanager.h"
#include "rectangle.h"
#include <celutil/debug.h>
#include <celmath/frustum.h>
#include <celmath/distance.h>
@ -7886,7 +7887,7 @@ void Renderer::setSolarSystemMaxDistance(float t)
SolarSystemMaxDistance = clamp(t, 1.0f, 10.0f);
}
void Renderer::getScreenSize(int* x, int* y, int* w, int* h) const
void Renderer::getViewport(int* x, int* y, int* w, int* h) const
{
GLint viewport[4];
glGetIntegerv(GL_VIEWPORT, viewport);
@ -7900,12 +7901,63 @@ void Renderer::getScreenSize(int* x, int* y, int* w, int* h) const
*h = viewport[3];
}
void Renderer::getScreenSize(std::array<int, 4>& viewport) const
void Renderer::getViewport(std::array<int, 4>& viewport) const
{
static_assert(sizeof(int) == sizeof(GLint), "int and GLint size mismatch");
glGetIntegerv(GL_VIEWPORT, &viewport[0]);
}
void Renderer::setViewport(int x, int y, int w, int h) const
{
glViewport(x, y, w, h);
}
void Renderer::setViewport(const std::array<int, 4>& viewport) const
{
glViewport(viewport[0], viewport[1], viewport[2], viewport[3]);
}
void Renderer::setScissor(int x, int y, int w, int h)
{
if ((m_GLStateFlag & ScissorTest) == 0)
{
glEnable(GL_SCISSOR_TEST);
m_GLStateFlag |= ScissorTest;
}
glScissor(x, y, w, h);
}
void Renderer::removeScissor()
{
if ((m_GLStateFlag & ScissorTest) != 0)
{
glDisable(GL_SCISSOR_TEST);
m_GLStateFlag &= ~ScissorTest;
}
}
void Renderer::enableMSAA()
{
if ((m_GLStateFlag & Multisaple) == 0)
{
glEnable(GL_MULTISAMPLE);
m_GLStateFlag |= Multisaple;
}
}
void Renderer::disableMSAA()
{
if ((m_GLStateFlag & Multisaple) != 0)
{
glDisable(GL_MULTISAMPLE);
m_GLStateFlag &= ~Multisaple;
}
}
bool Renderer::isMSAAEnabled() const
{
return (m_GLStateFlag & Multisaple) != 0;;
}
constexpr GLenum toGLFormat(Renderer::PixelFormat format)
{
return (GLenum) format;
@ -7918,3 +7970,93 @@ bool Renderer::captureFrame(int x, int y, int w, int h, Renderer::PixelFormat fo
return glGetError() == GL_NO_ERROR;
}
static void drawRectangle(const Renderer &renderer, const Rect &r)
{
uint32_t p = r.tex == nullptr ? 0 : ShaderProperties::HasTexture;
switch (r.nColors)
{
case 0:
break;
case 1:
p |= ShaderProperties::UniformColor;
break;
case 4:
p |= ShaderProperties::PerVertexColor;
break;
default:
fmt::fprintf(cerr, "Incorrect number of colors: %i\n", r.nColors);
}
auto prog = renderer.getShaderManager().getShader(ShaderProperties(p));
if (prog == nullptr)
return;
constexpr array<short, 8> texels = {0, 1, 1, 1, 1, 0, 0, 0};
array<float, 8> vertices = { r.x, r.y, r.x+r.w, r.y, r.x+r.w, r.y+r.h, r.x, r.y+r.h };
auto s = static_cast<GLsizeiptr>(memsize(vertices) + memsize(texels) + 4*4*sizeof(GLfloat));
static celgl::VertexObject vo{ GL_ARRAY_BUFFER, s, GL_DYNAMIC_DRAW };
vo.bindWritable();
if (!vo.initialized())
{
vo.allocate();
vo.setBufferData(texels.data(), memsize(vertices), memsize(texels));
vo.setVertices(2, GL_FLOAT);
vo.setTextureCoords(2, GL_SHORT, false, 0, memsize(vertices));
vo.setColors(4, GL_FLOAT, false, 0, memsize(vertices) + memsize(texels));
}
vo.setBufferData(vertices.data(), 0, memsize(vertices));
if (r.nColors == 4)
{
array<Vector4f, 4> ct;
for (size_t i = 0; i < 4; i++)
ct[i] = r.colors[i].toVector4();
vo.setBufferData(ct.data(), memsize(vertices) + memsize(texels), 4*4*sizeof(GLfloat));
}
prog->use();
if (r.tex != nullptr)
{
glEnable(GL_TEXTURE_2D);
r.tex->bind();
prog->samplerParam("tex") = 0;
}
if (r.nColors == 1)
prog->vec4Param("color") = r.colors[0].toVector4();
if (r.type != Rect::Type::BorderOnly)
{
vo.draw(GL_TRIANGLE_FAN, 4);
}
else
{
if (r.lw != 1.0f)
glLineWidth(r.lw);
vo.draw(GL_LINE_LOOP, 4);
if (r.lw != 1.0f)
glLineWidth(1.0f);
}
glUseProgram(0);
vo.unbind();
}
void Renderer::drawRectangle(const Rect &r) const
{
::drawRectangle(*this, r);
}
void Renderer::setRenderRegion(int x, int y, int width, int height, bool withScissor)
{
if (withScissor)
setScissor(x, y, width, height);
else
removeScissor();
setViewport(x, y, width, height);
resize(width, height);
}

View File

@ -21,11 +21,11 @@
#endif
#include <celengine/starcolors.h>
#include <celengine/rendcontext.h>
#include "celengine/vertexobject.h"
#include <celtxf/texturefont.h>
#include <vector>
#include <list>
#include <string>
#include "vertexobject.h"
class RendererWatcher;
@ -33,6 +33,7 @@ class FrameTree;
class ReferenceMark;
class CurvePlot;
class AsterismList;
class Rect;
struct LightSource
{
@ -246,8 +247,20 @@ class Renderer
void setOrbitMask(int);
int getScreenDpi() const;
void setScreenDpi(int);
void getScreenSize(int* x, int* y, int* w, int* h) const;
void getScreenSize(std::array<int, 4>& viewport) const;
// GL wrappers
void getViewport(int* x, int* y, int* w, int* h) const;
void getViewport(std::array<int, 4>& viewport) const;
void setViewport(int x, int y, int w, int h) const;
void setViewport(const std::array<int, 4>& viewport) const;
void setScissor(int x, int y, int w, int h);
void removeScissor();
void enableMSAA();
void disableMSAA();
bool isMSAAEnabled() const;
void drawRectangle(const Rect& r) const;
void setRenderRegion(int x, int y, int width, int height, bool withScissor = true);
const ColorTemperatureTable* getStarColorTable() const;
void setStarColorTable(const ColorTemperatureTable*);
bool getVideoSync() const;
@ -709,6 +722,13 @@ class Renderer
uint32_t frameCount;
int currentIntervalIndex{ 0 };
enum GLStateFlags
{
ScissorTest = 0x0001,
Multisaple = 0x0002,
};
int m_GLStateFlag { 0 };
celgl::VertexObject markerVO{ GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW };

View File

@ -24,6 +24,8 @@ set(CELESTIA_SOURCES
scriptmenu.h
url.cpp
url.h
view.cpp
view.h
)
set(CELX_SOURCES

View File

@ -145,7 +145,7 @@ bool AVICapture::captureFrame()
// Get the dimensions of the current viewport
int x, y, w, h;
renderer->getScreenSize(&x, &y, &w, &h);
renderer->getViewport(&x, &y, &w, &h);
x += (w - width) / 2;
y += (h - height) / 2;

View File

@ -52,6 +52,7 @@
#include <celutil/debug.h>
#include <celutil/color.h>
#include <celengine/vecgl.h>
#include <celengine/rectangle.h>
#ifdef CELX
#include <celephem/scriptobject.h>
@ -169,143 +170,15 @@ float ComputeRotationCoarseness(Simulation& sim)
}
View::View(View::Type _type,
Observer* _observer,
float _x, float _y,
float _width, float _height) :
type(_type),
observer(_observer),
parent(nullptr),
child1(nullptr),
child2(nullptr),
x(_x),
y(_y),
width(_width),
height(_height),
renderFlags(0),
labelMode(0),
zoom(1),
alternateZoom(1)
{
}
void View::mapWindowToView(float wx, float wy, float& vx, float& vy) const
{
vx = (wx - x) / width;
vy = (wy + (y + height - 1)) / height;
vx = (vx - 0.5f) * (width / height);
vy = 0.5f - vy;
}
void View::walkTreeResize(View* sibling, int sign) {
float ratio;
switch (parent->type)
{
case View::HorizontalSplit:
ratio = parent->height / (parent->height - height);
sibling->height *= ratio;
if (sign == 1)
{
sibling->y = parent->y + (sibling->y - parent->y) * ratio;
}
else
{
sibling->y = parent->y + (sibling->y - (y + height)) * ratio;
}
break;
case View::VerticalSplit:
ratio = parent->width / (parent->width - width);
sibling->width *= ratio;
if (sign == 1)
{
sibling->x = parent->x + (sibling->x - parent->x) * ratio;
}
else
{
sibling->x = parent->x + (sibling->x - (x + width) ) * ratio;
}
break;
case View::ViewWindow:
break;
}
if (sibling->child1) walkTreeResize(sibling->child1, sign);
if (sibling->child2) walkTreeResize(sibling->child2, sign);
}
bool View::walkTreeResizeDelta(View* v, float delta, bool check)
{
View *p=v;
int sign = -1;
float ratio;
double newSize;
if (v->child1)
{
if (!walkTreeResizeDelta(v->child1, delta, check))
return false;
}
if (v->child2)
{
if (!walkTreeResizeDelta(v->child2, delta, check))
return false;
}
while ( p != child1 && p != child2 && (p = p->parent) ) ;
if (p == child1) sign = 1;
switch (type)
{
case View::HorizontalSplit:
delta = -delta;
ratio = (p->height + sign * delta) / p->height;
newSize = v->height * ratio;
if (newSize <= .1) return false;
if (check) return true;
v->height = (float) newSize;
if (sign == 1)
{
v->y = p->y + (v->y - p->y) * ratio;
}
else
{
v->y = p->y + delta + (v->y - p->y) * ratio;
}
break;
case View::VerticalSplit:
ratio = (p->width + sign * delta) / p->width;
newSize = v->width * ratio;
if (newSize <= .1) return false;
if (check) return true;
v->width = (float) newSize;
if (sign == 1)
{
v->x = p->x + (v->x - p->x) * ratio;
}
else
{
v->x = p->x + delta + (v->x - p->x) * ratio;
}
break;
case View::ViewWindow:
break;
}
return true;
}
CelestiaCore::CelestiaCore() :
oldFOV(stdFOV)
{
oldFOV(stdFOV),
/* Get a renderer here so it may be queried for capabilities of the
underlying engine even before rendering is enabled. It's initRenderer()
routine will be called much later. */
renderer = new Renderer();
timer = new Timer();
execEnv = new CoreExecutionEnvironment(*this);
renderer(new Renderer()),
timer(new Timer()),
execEnv(new CoreExecutionEnvironment(*this))
{
for (int i = 0; i < KeyCount; i++)
{
@ -607,7 +480,8 @@ void CelestiaCore::mouseButtonDown(float x, float y, int button)
}
}
}
if (v2 != nullptr) {
if (v2 != nullptr)
{
// Look for common ancestor to v1 & v2 = split being draged.
View *p1 = v1, *p2 = v2;
while ( (p1 = p1->parent) != nullptr )
@ -661,8 +535,8 @@ void CelestiaCore::mouseButtonUp(float x, float y, int button)
float pickX, pickY;
float aspectRatio = ((float) width / (float) height);
(*activeView)->mapWindowToView((float) x / (float) width,
(float) y / (float) height,
pickX, pickY);
(float) y / (float) height,
pickX, pickY);
Vector3f pickRay =
sim->getActiveObserver()->getPickRay(pickX * aspectRatio, pickY);
@ -678,8 +552,8 @@ void CelestiaCore::mouseButtonUp(float x, float y, int button)
float pickX, pickY;
float aspectRatio = ((float) width / (float) height);
(*activeView)->mapWindowToView((float) x / (float) width,
(float) y / (float) height,
pickX, pickY);
(float) y / (float) height,
pickX, pickY);
Vector3f pickRay =
sim->getActiveObserver()->getPickRay(pickX * aspectRatio, pickY);
@ -742,9 +616,6 @@ void CelestiaCore::mouseMove(float x, float y)
if (views.size() > 1 && cursorHandler != nullptr)
{
/*View* v1 = 0; Unused*/
/*View* v2 = 0; Unused*/
for (const auto v : views)
{
if (v->type == View::ViewWindow)
@ -2355,55 +2226,43 @@ void CelestiaCore::draw()
// I'm not certain that a special case for one view is required; but,
// it's possible that there exists some broken hardware out there
// that has to fall back to software rendering if the scissor test
// is enable. To keep performance on this hypothetical hardware
// is enabled. To keep performance on this hypothetical hardware
// reasonable in the typical single view case, we'll use this
// scissorless special case. I'm only paranoid because I've been
// scissorless special case. I'm only paranoid because I've been
// burned by crap hardware so many times. cjl
glViewport(0, 0, width, height);
renderer->resize(width, height);
renderer->setRenderRegion(0, 0, width, height, false);
sim->render(*renderer);
}
else
{
glEnable(GL_SCISSOR_TEST);
for (const auto view : views)
{
if (view->type == View::ViewWindow)
{
glScissor((GLint) (view->x * width),
(GLint) (view->y * height),
(GLsizei) (view->width * width),
(GLsizei) (view->height * height));
glViewport((GLint) (view->x * width),
(GLint) (view->y * height),
(GLsizei) (view->width * width),
(GLsizei) (view->height * height));
renderer->resize((int) (view->width * width),
(int) (view->height * height));
view->switchTo(width, height);
sim->render(*renderer, *view->observer);
}
}
glDisable(GL_SCISSOR_TEST);
glViewport(0, 0, width, height);
renderer->setRenderRegion(0, 0, width, height, false);
}
GLboolean toggleAA = glIsEnabled(GL_MULTISAMPLE);
bool toggleAA = renderer->isMSAAEnabled();
if (toggleAA && (renderer->getRenderFlags() & Renderer::ShowCloudMaps))
glDisable(GL_MULTISAMPLE);
renderer->disableMSAA();
renderOverlay();
if (showConsole)
{
console.setFont(font);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
console.setColor(1.0f, 1.0f, 1.0f, 1.0f);
console.begin();
glTranslatef(0.0f, 200.0f, 0.0f);
console.moveBy(0.0f, 200.0f, 0.0f);
console.render(ConsolePageRows);
console.end();
}
if (toggleAA)
glEnable(GL_MULTISAMPLE);
renderer->enableMSAA();
if (movieCapture != nullptr && recording)
movieCapture->captureFrame();
@ -2432,9 +2291,11 @@ void CelestiaCore::resize(GLsizei w, GLsizei h)
if (h == 0)
h = 1;
glViewport(0, 0, w, h);
if (renderer != nullptr)
{
renderer->setViewport(0, 0, w, h);
renderer->resize(w, h);
}
if (overlay != nullptr)
overlay->setWindowSize(w, h);
console.setScale(w, h);
@ -2497,88 +2358,35 @@ void CelestiaCore::setViewChanged()
void CelestiaCore::splitView(View::Type type, View* av, float splitPos)
{
setViewChanged();
if (type == View::ViewWindow)
return;
if (av == nullptr)
av = (*activeView);
bool vertical = ( type == View::VerticalSplit );
Observer* o = sim->addObserver();
bool tooSmall = false;
av = *activeView;
switch (type) // If active view is too small, don't split it.
{
case View::HorizontalSplit:
if (av->height < 0.2f) tooSmall = true;
break;
case View::VerticalSplit:
if (av->width < 0.2f) tooSmall = true;
break;
case View::ViewWindow:
return;
break;
}
if (tooSmall)
if (!av->isSplittable(type))
{
flash(_("View too small to be split"));
return;
}
flash(_("Added view"));
setViewChanged();
Observer* o = sim->addObserver();
// Make the new observer a copy of the old one
// TODO: This works, but an assignment operator for Observer
// should be defined.
*o = *(sim->getActiveObserver());
float w1, h1, w2, h2;
if (vertical)
{
w1 = av->width * splitPos;
w2 = av->width - w1;
h1 = av->height;
h2 = av->height;
}
else
{
w1 = av->width;
w2 = av->width;
h1 = av->height * splitPos;
h2 = av->height - h1;
}
View* split = new View(type,
0,
av->x,
av->y,
av->width,
av->height);
split->parent = av->parent;
if (av->parent != nullptr)
{
if (av->parent->child1 == av)
av->parent->child1 = split;
else
av->parent->child2 = split;
}
split->child1 = av;
av->width = w1;
av->height = h1;
av->parent = split;
View* view = new View(View::ViewWindow,
o,
av->x + (vertical ? w1 : 0),
av->y + (vertical ? 0 : h1),
w2, h2);
split->child2 = view;
view->parent = split;
view->zoom = av->zoom;
View* split, *view;
av->split(type, o, splitPos, &split, &view);
views.push_back(split);
views.push_back(view);
setFOVFromZoom();
flash(_("Added view"));
}
void CelestiaCore::setFOVFromZoom()
@ -2605,29 +2413,23 @@ void CelestiaCore::singleView(View* av)
setViewChanged();
if (av == nullptr)
av = (*activeView);
av = *activeView;
list<View*>::iterator i = views.begin();
while(i != views.end())
{
if ((*i) != av)
{
sim->removeObserver((*i)->observer);
delete (*i)->observer;
sim->removeObserver((*i)->getObserver());
delete (*i)->getObserver();
delete (*i);
i=views.erase(i);
i = views.erase(i);
}
else
i++;
++i;
}
av->x = 0.0f;
av->y = 0.0f;
av->width = 1.0f;
av->height = 1.0f;
av->parent = nullptr;
av->child1 = nullptr;
av->child2 = nullptr;
av->reset();
activeView = views.begin();
sim->setActiveObserver((*activeView)->observer);
@ -2636,60 +2438,37 @@ void CelestiaCore::singleView(View* av)
void CelestiaCore::setActiveView(View* v)
{
activeView = find(views.begin(),views.end(),v);
activeView = find(views.begin(), views.end(), v);
sim->setActiveObserver((*activeView)->observer);
}
void CelestiaCore::deleteView(View* v)
{
if (v == nullptr)
v = (*activeView);
v = *activeView;
if (v->parent == nullptr) return;
if (v->isRootView())
return;
//Erase view and parent view from views
list<View*>::iterator i = views.begin();
while(i != views.end())
for (auto i = views.begin(); i != views.end(); )
{
if ((*i == v) || (*i == v->parent))
i=views.erase(i);
i = views.erase(i);
else
i++;
++i;
}
int sign;
View *sibling;
if (v->parent->child1 == v)
{
sibling = v->parent->child2;
sign = -1;
}
else
{
sibling = v->parent->child1;
sign = 1;
}
sibling->parent = v->parent->parent;
if (v->parent->parent != nullptr) {
if (v->parent->parent->child1 == v->parent)
v->parent->parent->child1 = sibling;
else
v->parent->parent->child2 = sibling;
}
sim->removeObserver(v->getObserver());
delete(v->getObserver());
auto sibling = View::remove(v);
v->walkTreeResize(sibling, sign);
sim->removeObserver(v->observer);
delete(v->observer);
View* nextActiveView = sibling;
while (nextActiveView->type != View::ViewWindow)
nextActiveView = nextActiveView->child1;
activeView = find(views.begin(),views.end(),nextActiveView);
activeView = find(views.begin(), views.end(), nextActiveView);
sim->setActiveObserver((*activeView)->observer);
delete(v->parent);
delete(v);
if (!showActiveViewFrame)
flashFrameStart = currentTime;
setFOVFromZoom();
@ -3260,66 +3039,12 @@ static void displaySelectionName(Overlay& overlay,
#endif
void CelestiaCore::setScriptImage(float duration,
float xoffset,
float yoffset,
float alpha,
const fs::path& filename,
bool fitscreen)
void CelestiaCore::setScriptImage(std::unique_ptr<OverlayImage> &&_image)
{
if (image == nullptr || image->isNewImage(filename))
{
delete image;
image = new CelestiaCore::OverlayImage(filename, overlay);
}
image = std::move(_image);
image->setStartTime((float) currentTime);
image->setDuration(duration);
image->setOffset(xoffset, yoffset);
image->setAlpha(alpha);
image->fitScreen(fitscreen);
}
CelestiaCore::OverlayImage::OverlayImage(fs::path f, Overlay* o) :
filename(std::move(f)),
overlay(o)
{
texture = LoadTextureFromFile(fs::path("images") / filename);
}
void CelestiaCore::OverlayImage::render(float curr_time, int width, int height)
{
if (texture == nullptr || (curr_time >= start + duration))
return;
float xSize = texture->getWidth();
float ySize = texture->getHeight();
// center overlay image horizontally if offsetX = 0
float left = (width * (1 + offsetX) - xSize)/2;
// center overlay image vertically if offsetY = 0
float bottom = (height * (1 + offsetY) - ySize)/2;
if (fitscreen)
{
float coeffx = xSize / width; // overlay pict width/view window width ratio
float coeffy = ySize / height; // overlay pict height/view window height ratio
xSize = xSize / coeffx; // new overlay picture width size to fit viewport
ySize = ySize / coeffy; // new overlay picture height to fit viewport
left = (width - xSize) / 2; // to be sure overlay pict is centered in viewport
bottom = 0; // overlay pict locked at bottom of screen
}
glEnable(GL_TEXTURE_2D);
texture->bind();
Overlay::Rectangle r(left, bottom, xSize, ySize, {Color::White, alpha}, Overlay::RectType::Textured);
overlay->rect(r);
}
void CelestiaCore::renderOverlay()
{
#ifdef CELX
@ -3343,51 +3068,34 @@ void CelestiaCore::renderOverlay()
if (runningScript)
{
#endif
if (image)
if (image != nullptr)
image->render((float) currentTime, width, height);
}
if (views.size() > 1)
{
Overlay::Rectangle r(0, 0, 0, 0, frameColor, Overlay::RectType::Outlined, 1);
// Render a thin border arround all views
if (showViewFrames || resizeSplit)
{
for(const auto v : views)
{
if (v->type == View::ViewWindow)
{
r.x = v->x * width;
r.y = v->y * height;
r.w = v->width * width - 1;
r.h = v->height * height - 1;
overlay->rect(r);
}
v->drawBorder(width, height, frameColor);
}
}
// Render a very simple border around the active view
View* av = *activeView;
r.x = av->x * width;
r.y = av->y * height;
r.w = av->width * width - 1;
r.h = av->height * height - 1;
if (showActiveViewFrame)
{
r.colors[0] = activeFrameColor;
r.lw = 2;
overlay->rect(r);
av->drawBorder(width, height, activeFrameColor, 2);
}
if (currentTime < flashFrameStart + 0.5)
{
float alpha = (float) (1.0 - (currentTime - flashFrameStart) / 0.5);
r.colors[0] = {activeFrameColor, alpha};
r.lw = 8;
overlay->rect(r);
av->drawBorder(width, height, {activeFrameColor, alpha}, 8);
}
}
@ -3415,20 +3123,18 @@ void CelestiaCore::renderOverlay()
if (dateWidth > dateStrWidth) dateStrWidth = dateWidth;
// Time and date
glPushMatrix();
glColor4f(0.7f, 0.7f, 1.0f, 1.0f);
glTranslatef( (float) (width - dateStrWidth),
(float) (height - fontHeight),
0.0f);
overlay->savePos();
overlay->setColor(0.7f, 0.7f, 1.0f, 1.0f);
overlay->moveBy(width - dateStrWidth, height - fontHeight);
overlay->beginText();
overlay->print(dateStr);
if (lightTravelFlag && lt > 0.0)
{
glColor4f(0.42f, 1.0f, 1.0f, 1.0f);
overlay->setColor(0.42f, 1.0f, 1.0f, 1.0f);
*overlay << _(" LT");
glColor4f(0.7f, 0.7f, 1.0f, 1.0f);
overlay->setColor(0.7f, 0.7f, 1.0f, 1.0f);
}
*overlay << '\n';
@ -3455,21 +3161,21 @@ void CelestiaCore::renderOverlay()
if (sim->getPauseState() == true)
{
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
overlay->setColor(1.0f, 0.0f, 0.0f, 1.0f);
*overlay << _(" (Paused)");
}
}
overlay->endText();
glPopMatrix();
overlay->restorePos();
}
if (hudDetail > 0 && (overlayElements & ShowVelocity))
{
// Speed
glPushMatrix();
glTranslatef(0.0f, (float) (fontHeight * 2 + 5), 0.0f);
glColor4f(0.7f, 0.7f, 1.0f, 1.0f);
overlay->savePos();
overlay->moveBy(0.0f, fontHeight * 2 + 5);
overlay->setColor(0.7f, 0.7f, 1.0f, 1.0f);
overlay->beginText();
*overlay << '\n';
@ -3492,7 +3198,7 @@ void CelestiaCore::renderOverlay()
displaySpeed(*overlay, sim->getObserver().getVelocity().norm());
overlay->endText();
glPopMatrix();
overlay->restorePos();
}
Universe *u = sim->getUniverse();
@ -3500,11 +3206,10 @@ void CelestiaCore::renderOverlay()
if (hudDetail > 0 && (overlayElements & ShowFrame))
{
// Field of view and camera mode in lower right corner
glPushMatrix();
glTranslatef((float) (width - emWidth * 15),
(float) (fontHeight * 3 + 5), 0.0f);
overlay->savePos();
overlay->moveBy(width - emWidth * 15, fontHeight * 3 + 5);
overlay->beginText();
glColor4f(0.6f, 0.6f, 1.0f, 1);
overlay->setColor(0.6f, 0.6f, 1.0f, 1);
if (sim->getObserverMode() == Observer::Travelling)
{
@ -3562,23 +3267,23 @@ void CelestiaCore::renderOverlay()
}
}
glColor4f(0.7f, 0.7f, 1.0f, 1.0f);
overlay->setColor(0.7f, 0.7f, 1.0f, 1.0f);
// Field of view
float fov = radToDeg(sim->getActiveObserver()->getFOV());
fmt::fprintf(*overlay, _("FOV: %s (%.2fx)\n"),
angleToStr(fov), (*activeView)->zoom);
overlay->endText();
glPopMatrix();
overlay->restorePos();
}
// Selection info
Selection sel = sim->getSelection();
if (!sel.empty() && hudDetail > 0 && (overlayElements & ShowSelection))
{
glPushMatrix();
glColor4f(0.7f, 0.7f, 1.0f, 1.0f);
glTranslatef(0.0f, (float) (height - titleFont->getHeight()), 0.0f);
overlay->savePos();
overlay->setColor(0.7f, 0.7f, 1.0f, 1.0f);
overlay->moveBy(0.0f, height - titleFont->getHeight());
overlay->beginText();
Vector3d v = sel.getPosition(sim->getTime()).offsetFromKm(sim->getObserver().getPosition());
@ -3608,9 +3313,8 @@ void CelestiaCore::renderOverlay()
}
overlay->setFont(titleFont);
*overlay << selectionNames;
*overlay << selectionNames << '\n';
overlay->setFont(font);
*overlay << '\n';
displayStarInfo(*overlay,
hudDetail,
*(sel.star()),
@ -3636,9 +3340,8 @@ void CelestiaCore::renderOverlay()
}
overlay->setFont(titleFont);
*overlay << selectionNames;
*overlay << selectionNames << '\n';
overlay->setFont(font);
*overlay << '\n';
displayDSOinfo(*overlay,
*sel.deepsky(),
astro::kilometersToLightYears(v.norm()) - sel.deepsky()->getRadius());
@ -3656,11 +3359,11 @@ void CelestiaCore::renderOverlay()
// Skip displaying the primary name if there's a localized version
// of the name.
vector<string>::const_iterator firstName = names.begin();
auto firstName = names.begin();
if (sel.body()->hasLocalizedName())
firstName++;
++firstName;
for (vector<string>::const_iterator iter = firstName; iter != names.end(); iter++)
for (auto iter = firstName; iter != names.end(); ++iter)
{
if (iter != firstName)
selectionNames += " / ";
@ -3699,9 +3402,7 @@ void CelestiaCore::renderOverlay()
*overlay << sel.location()->getName(true).c_str();
overlay->setFont(font);
*overlay << '\n';
displayLocationInfo(*overlay,
*(sel.location()),
v.norm());
displayLocationInfo(*overlay, *(sel.location()), v.norm());
break;
default:
@ -3759,18 +3460,19 @@ void CelestiaCore::renderOverlay()
overlay->endText();
glPopMatrix();
overlay->restorePos();
}
// Text input
if (textEnterMode & KbAutoComplete)
{
overlay->setFont(titleFont);
glPushMatrix();
Overlay::Rectangle r(0, 0, width, 100, consoleColor, Overlay::RectType::Filled);
overlay->rect(r);
glTranslatef(0.0f, fontHeight * 3.0f + 35.0f, 0.0f);
glColor4f(0.6f, 0.6f, 1.0f, 1.0f);
overlay->savePos();
Rect r(0, 0, width, 100);
r.setColor(consoleColor);
overlay->drawRectangle(r);
overlay->moveBy(0.0f, fontHeight * 3.0f + 35.0f);
overlay->setColor(0.6f, 0.6f, 1.0f, 1.0f);
overlay->beginText();
fmt::fprintf(*overlay, _("Target name: %s"), typedText);
overlay->endText();
@ -3780,7 +3482,7 @@ void CelestiaCore::renderOverlay()
int nb_cols = 4;
int nb_lines = 3;
int start = 0;
glTranslatef(3.0f, -font->getHeight() - 3.0f, 0.0f);
overlay->moveBy(3.0f, -font->getHeight() - 3.0f);
vector<std::string>::const_iterator iter = typedTextCompletion.begin();
if (typedTextCompletionIdx >= nb_cols * nb_lines)
{
@ -3789,22 +3491,22 @@ void CelestiaCore::renderOverlay()
}
for (int i=0; iter < typedTextCompletion.end() && i < nb_cols; i++)
{
glPushMatrix();
overlay->savePos();
overlay->beginText();
for (int j = 0; iter < typedTextCompletion.end() && j < nb_lines; iter++, j++)
{
if (i * nb_lines + j == typedTextCompletionIdx - start)
glColor4f(1.0f, 0.6f, 0.6f, 1);
overlay->setColor(1.0f, 0.6f, 0.6f, 1);
else
glColor4f(0.6f, 0.6f, 1.0f, 1);
overlay->setColor(0.6f, 0.6f, 1.0f, 1);
*overlay << *iter << "\n";
}
overlay->endText();
glPopMatrix();
glTranslatef((float) (width/nb_cols), 0.0f, 0.0f);
overlay->restorePos();
overlay->moveBy((float) (width/nb_cols), 0.0f, 0.0f);
}
}
glPopMatrix();
overlay->restorePos();
overlay->setFont(font);
}
@ -3828,17 +3530,17 @@ void CelestiaCore::renderOverlay()
y -= fontHeight;
overlay->setFont(titleFont);
glPushMatrix();
overlay->savePos();
float alpha = 1.0f;
if (currentTime > messageStart + messageDuration - 0.5)
alpha = (float) ((messageStart + messageDuration - currentTime) / 0.5);
glColor4f(textColor.red(), textColor.green(), textColor.blue(), alpha);
glTranslatef((float) x, (float) y, 0.0f);
overlay->setColor(textColor.red(), textColor.green(), textColor.blue(), alpha);
overlay->moveBy(x, y);
overlay->beginText();
*overlay << messageText;
overlay->endText();
glPopMatrix();
overlay->restorePos();
overlay->setFont(font);
}
@ -3846,18 +3548,18 @@ void CelestiaCore::renderOverlay()
{
int movieWidth = movieCapture->getWidth();
int movieHeight = movieCapture->getHeight();
glPushMatrix();
Color color(1, 0, 0, 1);
glColor(color);
Overlay::Rectangle r((width - movieWidth) / 2 - 1,
(height - movieHeight) / 2 - 1,
movieWidth + 1,
movieHeight + 1,
color,
Overlay::RectType::Outlined);
overlay->rect(r);
glTranslatef((float) ((width - movieWidth) / 2),
(float) ((height + movieHeight) / 2 + 2), 0.0f);
overlay->savePos();
Color color(1.0f, 0.0f, 0.0f, 1.0f);
overlay->setColor(color);
Rect r((width - movieWidth) / 2 - 1,
(height - movieHeight) / 2 - 1,
movieWidth + 1,
movieHeight + 1);
r.setColor(color);
r.setType(Rect::Type::BorderOnly);
overlay->drawRectangle(r);
overlay->moveBy((float) ((width - movieWidth) / 2),
(float) ((height + movieHeight) / 2 + 2));
overlay->beginText();
fmt::fprintf(*overlay, _("%dx%d at %f fps %s"),
movieWidth, movieHeight,
@ -3865,12 +3567,11 @@ void CelestiaCore::renderOverlay()
recording ? _("Recording") : _("Paused"));
overlay->endText();
glPopMatrix();
overlay->restorePos();
glPushMatrix();
glTranslatef((float) ((width + movieWidth) / 2 - emWidth * 5),
(float) ((height + movieHeight) / 2 + 2),
0.0f);
overlay->savePos();
overlay->moveBy((float) ((width + movieWidth) / 2 - emWidth * 5),
(float) ((height + movieHeight) / 2 + 2));
float sec = movieCapture->getFrameCount() /
movieCapture->getFrameRate();
auto min = (int) (sec / 60);
@ -3878,28 +3579,27 @@ void CelestiaCore::renderOverlay()
overlay->beginText();
fmt::fprintf(*overlay, "%3d:%05.2f", min, sec);
overlay->endText();
glPopMatrix();
overlay->restorePos();
glPushMatrix();
glTranslatef((float) ((width - movieWidth) / 2),
(float) ((height - movieHeight) / 2 - fontHeight - 2),
0.0f);
overlay->savePos();
overlay->moveBy((float) ((width - movieWidth) / 2),
(float) ((height - movieHeight) / 2 - fontHeight - 2));
overlay->beginText();
*overlay << _("F11 Start/Pause F12 Stop");
overlay->endText();
glPopMatrix();
overlay->restorePos();
glPopMatrix();
overlay->restorePos();
}
if (editMode)
{
glPushMatrix();
glTranslatef((float) ((width - font->getWidth(_("Edit Mode"))) / 2),
(float) (height - fontHeight), 0.0f);
glColor4f(1, 0, 1, 1);
overlay->savePos();
overlay->moveBy((float) ((width - font->getWidth(_("Edit Mode"))) / 2),
(float) (height - fontHeight));
overlay->setColor(1, 0, 1, 1);
*overlay << _("Edit Mode");
glPopMatrix();
overlay->restorePos();
}
// Show logo at start
@ -4213,10 +3913,12 @@ bool CelestiaCore::initSimulation(const fs::path& configFileName,
}
sim = new Simulation(universe);
if((renderer->getRenderFlags() & Renderer::ShowAutoMag) == 0)
sim->setFaintestVisible(config->faintestVisible);
if ((renderer->getRenderFlags() & Renderer::ShowAutoMag) == 0)
{
sim->setFaintestVisible(config->faintestVisible);
}
View* view = new View(View::ViewWindow, sim->getActiveObserver(), 0.0f, 0.0f, 1.0f, 1.0f);
View* view = new View(View::ViewWindow, renderer, sim->getActiveObserver(), 0.0f, 0.0f, 1.0f, 1.0f);
views.push_back(view);
activeView = views.begin();

View File

@ -21,11 +21,13 @@
#include <celengine/universe.h>
#include <celengine/render.h>
#include <celengine/simulation.h>
#include <celengine/overlayimage.h>
#include <GL/glew.h>
#include "configfile.h"
#include "favorites.h"
#include "destination.h"
#include "moviecapture.h"
#include "view.h"
#ifdef CELX
#include "celx.h"
#endif
@ -47,40 +49,6 @@ public:
virtual void update(const std::string&) = 0;
};
class View
{
public:
enum Type {
ViewWindow = 1,
HorizontalSplit = 2,
VerticalSplit = 3
};
View(Type, Observer*, float, float, float, float);
void mapWindowToView(float, float, float&, float&) const;
public:
Type type;
Observer* observer;
View *parent;
View *child1;
View *child2;
float x;
float y;
float width;
float height;
uint64_t renderFlags;
int labelMode;
float zoom;
float alternateZoom;
void walkTreeResize(View*, int);
bool walkTreeResizeDelta(View*, float, bool);
};
class CelestiaCore // : public Watchable<CelestiaCore>
{
public:
@ -197,37 +165,6 @@ class CelestiaCore // : public Watchable<CelestiaCore>
ShowFrame = 0x010,
};
private:
class OverlayImage
{
public:
OverlayImage(fs::path, Overlay*);
~OverlayImage() { delete texture; }
OverlayImage() =default;
OverlayImage(OverlayImage&) =delete;
OverlayImage(OverlayImage&&) =delete;
void render(float, int, int);
inline bool isNewImage(const fs::path& f) { return filename != f; }
void setStartTime(float t) { start = t; }
void setDuration(float t) { duration = t; }
void setOffset(float x, float y) { offsetX = x; offsetY = y; }
void setAlpha(float t) { alpha = t; }
void fitScreen(bool t) { fitscreen = t; }
private:
float start{ 0.0f };
float duration{ 0.0f };
float offsetX{ 0.0f };
float offsetY{ 0.0f };
float alpha{ 0.0f };
bool fitscreen{ false };
fs::path filename;
Texture* texture{ nullptr };
Overlay* overlay;
};
public:
CelestiaCore();
~CelestiaCore();
@ -383,7 +320,7 @@ class CelestiaCore // : public Watchable<CelestiaCore>
void fatalError(const std::string&, bool visual = true);
void setScriptImage(float, float, float, float, const fs::path&, bool);
void setScriptImage(std::unique_ptr<OverlayImage>&&);
const std::string& getTypedText() const { return typedText; }
void setTypedText(const char *);
@ -425,7 +362,7 @@ class CelestiaCore // : public Watchable<CelestiaCore>
const Color activeFrameColor{ 0.5f, 0.5f, 1.0f, 1.0f };
const Color consoleColor{ 0.7f, 0.7f, 1.0f, 0.2f };
OverlayImage *image{ nullptr };
std::unique_ptr<OverlayImage> image;
std::string typedText;
std::vector<std::string> typedTextCompletion;

View File

@ -28,6 +28,7 @@
#include "url.h"
#include "imagecapture.h"
#include "celestiacore.h"
#include "view.h"
using namespace Eigen;
@ -282,7 +283,7 @@ int celestia_getscreendimension(lua_State* l)
// Get the dimensions of the current viewport
int w, h;
CelestiaCore* appCore = to_celestia(l, 1);
appCore->getRenderer()->getScreenSize(nullptr, nullptr, &w, &h);
appCore->getRenderer()->getViewport(nullptr, nullptr, &w, &h);
lua_pushnumber(l, w);
lua_pushnumber(l, h);
return 2;
@ -1916,7 +1917,7 @@ static int celestia_takescreenshot(lua_State* l)
// Get the dimensions of the current viewport
array<GLint, 4> viewport;
appCore->getRenderer()->getScreenSize(viewport);
appCore->getRenderer()->getViewport(viewport);
fs::path path = appCore->getConfig()->scriptScreenshotDirectory;
@ -2081,7 +2082,14 @@ static int celestia_overlay(lua_State* l)
else
fitscreen = (bool) Celx_SafeGetNumber(l, 7, WrongType, "Sixth argument to celestia:overlay must be a number or a boolean(fitscreen)", 0);
appCore->setScriptImage(duration, xoffset, yoffset, alpha, filename, fitscreen);
auto image = unique_ptr<OverlayImage>(new OverlayImage(filename, appCore->getRenderer()));
image->setDuration(duration);
image->setFadeAfter(duration); // FIXME
image->setOffset(xoffset, yoffset);
image->setColor({Color::White, alpha}); // FIXME
image->fitScreen(fitscreen);
appCore->setScriptImage(std::move(image));
return 0;
}

View File

@ -773,39 +773,57 @@ Command* CommandParser::parseCommand()
}
else if (commandName == "overlay")
{
float duration;
float xoffset;
float yoffset;
float alpha;
float duration = 3.0f;
float fadeafter;
float xoffset = 0.0f;
float yoffset = 0.0f;
float alpha = 1.0f;
bool hasAlpha = true;
string filename;
bool fitscreen;
bool fitscreen = false;
Color color(Color::White);
if(!paramList->getNumber("duration", duration))
duration = 3;
if(!paramList->getNumber("xoffset", xoffset))
xoffset = 0.0;
if(!paramList->getNumber("yoffset", yoffset))
yoffset = 0.0;
if(!paramList->getNumber("alpha", alpha))
alpha = 1;
if(!paramList->getString("filename", filename))
filename = "";
if(!paramList->getBoolean("fitscreen", fitscreen))
paramList->getNumber("duration", duration);
paramList->getNumber("xoffset", xoffset);
paramList->getNumber("yoffset", yoffset);
if (paramList->getNumber("alpha", alpha))
hasAlpha = true;
paramList->getString("filename", filename);
if (!paramList->getBoolean("fitscreen", fitscreen))
{
int f;
if(!paramList->getNumber("fitscreen", f))
fitscreen = false;
else
fitscreen = (bool) f;
int f;
// backward compatibility with celestia ed implementation
if (paramList->getNumber("fitscreen", f))
fitscreen = (bool) f;
}
cmd = new CommandScriptImage(duration, xoffset, yoffset, alpha, filename, fitscreen);
array<Color, 4> colors;
paramList->getColor("color", color);
colors.fill(hasAlpha ? Color(color, alpha) : color);
if (paramList->getColor("colortop", color))
colors[0] = colors[1] = hasAlpha ? Color(color, alpha) : color;
if (paramList->getColor("colorbottom", color))
colors[2] = colors[3] = hasAlpha ? Color(color, alpha) : color;
if (paramList->getColor("colortopleft", color))
colors[0] = hasAlpha ? Color(color, alpha) : color;
if (paramList->getColor("colortopright", color))
colors[1] = hasAlpha ? Color(color, alpha) : color;
if (paramList->getColor("colorbottomright", color))
colors[2] = hasAlpha ? Color(color, alpha) : color;
if (paramList->getColor("colorbottomleft", color))
colors[3] = hasAlpha ? Color(color, alpha) : color;
if (!paramList->getNumber("fadeafter", fadeafter))
fadeafter = duration;
cmd = new CommandScriptImage(duration, fadeafter, xoffset, yoffset, filename, fitscreen, colors);
}
else if (commandName == "verbosity")
{
int level;
if(!paramList->getNumber("level", level))
if (!paramList->getNumber("level", level))
level = 2;
cmd = new CommandVerbosity(level);

View File

@ -649,7 +649,7 @@ void CommandCapture::process(ExecutionEnvironment& env)
// Get the dimensions of the current viewport
array<int, 4> viewport;
r->getScreenSize(viewport);
r->getViewport(viewport);
if (compareIgnoringCase(type, "jpeg") == 0)
{
@ -952,21 +952,30 @@ double RepeatCommand::getDuration() const
}
// ScriptImage command
CommandScriptImage::CommandScriptImage(float _duration, float _xoffset,
float _yoffset, float _alpha,
std::string _filename, bool _fitscreen) :
CommandScriptImage::CommandScriptImage(float _duration, float _fadeafter,
float _xoffset, float _yoffset,
fs::path _filename,
bool _fitscreen,
array<Color,4> &_colors) :
duration(_duration),
fadeafter(_fadeafter),
xoffset(_xoffset),
yoffset(_yoffset),
alpha(_alpha),
filename(std::move(_filename)),
fitscreen(_fitscreen)
{
copy(_colors.begin(), _colors.end(), colors.begin());
}
void CommandScriptImage::process(ExecutionEnvironment& env)
{
env.getCelestiaCore()->setScriptImage(duration, xoffset, yoffset, alpha, filename, fitscreen);
auto image = unique_ptr<OverlayImage>(new OverlayImage(filename, env.getRenderer()));
image->setDuration(duration);
image->setFadeAfter(fadeafter);
image->setOffset(xoffset, yoffset);
image->setColor(colors);
image->fitScreen(fitscreen);
env.getCelestiaCore()->setScriptImage(std::move(image));
}
// Verbosity command

View File

@ -12,6 +12,7 @@
#define MAX_CONSTELLATIONS 100
#include <array>
#include <iostream>
#include <celengine/execenv.h>
#include <celengine/astro.h>
@ -716,17 +717,17 @@ class RepeatCommand : public Command
class CommandScriptImage : public InstantaneousCommand
{
public:
CommandScriptImage(float _duration, float _xoffset, float _yoffset,
float _alpha, std::string, bool _fitscreen);
CommandScriptImage(float, float, float, float, fs::path, bool, std::array<Color, 4>&);
void process(ExecutionEnvironment&);
private:
double duration;
float duration;
float fadeafter;
float xoffset;
float yoffset;
float alpha;
std::string filename;
fs::path filename;
int fitscreen;
std::array<Color, 4> colors;
};
class CommandVerbosity : public InstantaneousCommand

View File

@ -1124,7 +1124,7 @@ static void captureImage(const char* filename, AppData* app)
{
/* Get the dimensions of the current viewport */
array<int, 4> viewport;
app->renderer->getScreenSize(viewport);
app->renderer->getViewport(viewport);
bool success = false;
ContentType type = DetermineFileType(filename);
@ -1183,7 +1183,7 @@ static void captureMovie(const char* filename, int aspect, float fps, float qual
{
/* Get the dimensions of the current viewport */
array<int, 4> viewport;
app->renderer->getScreenSize(viewport);
app->renderer->getViewport(viewport);
MovieCapture* movieCapture = new OggTheoraCapture(app->renderer);
switch (aspect)

View File

@ -338,7 +338,7 @@ bool OggTheoraCapture::captureFrame()
// Get the dimensions of the current viewport
int x, y, w, h;
renderer->getScreenSize(&x, &y, &w, &h);
renderer->getViewport(&x, &y, &w, &h);
x += (w - frame_x) / 2;
y += (h - frame_y) / 2;

View File

@ -0,0 +1,266 @@
// view.cpp
//
// Copyright (C) 2001-2019, Celestia Development Team
//
// 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/rectangle.h>
#include <celengine/render.h>
#include <celutil/color.h>
#include "view.h"
#include<iostream>
View::View(View::Type _type,
Renderer *_renderer,
Observer *_observer,
float _x, float _y,
float _width, float _height) :
type(_type),
renderer(_renderer),
observer(_observer),
x(_x),
y(_y),
width(_width),
height(_height)
{
}
void View::mapWindowToView(float wx, float wy, float& vx, float& vy) const
{
vx = (wx - x) / width;
vy = (wy + (y + height - 1)) / height;
vx = (vx - 0.5f) * (width / height);
vy = 0.5f - vy;
}
void View::walkTreeResize(View* sibling, int sign)
{
float ratio;
switch (parent->type)
{
case View::HorizontalSplit:
ratio = parent->height / (parent->height - height);
sibling->height *= ratio;
if (sign == 1)
{
sibling->y = parent->y + (sibling->y - parent->y) * ratio;
}
else
{
sibling->y = parent->y + (sibling->y - (y + height)) * ratio;
}
break;
case View::VerticalSplit:
ratio = parent->width / (parent->width - width);
sibling->width *= ratio;
if (sign == 1)
{
sibling->x = parent->x + (sibling->x - parent->x) * ratio;
}
else
{
sibling->x = parent->x + (sibling->x - (x + width) ) * ratio;
}
break;
case View::ViewWindow:
break;
}
if (sibling->child1 != nullptr)
walkTreeResize(sibling->child1, sign);
if (sibling->child2 != nullptr)
walkTreeResize(sibling->child2, sign);
}
bool View::walkTreeResizeDelta(View* v, float delta, bool check)
{
View *p = v;
int sign = -1;
float ratio;
double newSize;
if (v->child1 != nullptr)
{
if (!walkTreeResizeDelta(v->child1, delta, check))
return false;
}
if (v->child2 != nullptr)
{
if (!walkTreeResizeDelta(v->child2, delta, check))
return false;
}
while ( p != child1 && p != child2 && (p = p->parent) != nullptr ) ;
if (p == child1)
sign = 1;
switch (type)
{
case View::HorizontalSplit:
delta = -delta;
ratio = (p->height + sign * delta) / p->height;
newSize = v->height * ratio;
if (newSize <= .1)
return false;
if (check)
return true;
v->height = (float) newSize;
if (sign == 1)
{
v->y = p->y + (v->y - p->y) * ratio;
}
else
{
v->y = p->y + delta + (v->y - p->y) * ratio;
}
break;
case View::VerticalSplit:
ratio = (p->width + sign * delta) / p->width;
newSize = v->width * ratio;
if (newSize <= .1)
return false;
if (check)
return true;
v->width = (float) newSize;
if (sign == 1)
{
v->x = p->x + (v->x - p->x) * ratio;
}
else
{
v->x = p->x + delta + (v->x - p->x) * ratio;
}
break;
case View::ViewWindow:
break;
}
return true;
}
Observer* View::getObserver() const
{
return observer;
}
void View::switchTo(int gWidth, int gHeight)
{
renderer->setRenderRegion(int(x * gWidth),
int(y * gHeight),
int(width * gWidth),
int(height * gHeight));
}
bool View::isSplittable(Type type) const
{
// If active view is too small, don't split it.
return (type == View::HorizontalSplit && height >= 0.2f) ||
(type == View::VerticalSplit && width >= 0.2f);
}
bool View::isRootView() const
{
return parent == nullptr;
}
void View::split(Type type, Observer *o, float splitPos, View **split, View **view)
{
float w1, h1, w2, h2, x1, y1;
w1 = w2 = width;
h1 = h2 = height;
x1 = x;
y1 = y;
if (type == View::VerticalSplit)
{
w1 *= splitPos;
w2 -= w1;
x1 += w1;
}
else
{
h1 *= splitPos;
h2 -= h1;
y1 += h1;
}
*split = new View(type,
renderer,
nullptr,
x, y, width, height);
(*split)->parent = parent;
if (parent != nullptr)
{
if (parent->child1 == this)
parent->child1 = *split;
else
parent->child2 = *split;
}
(*split)->child1 = this;
width = w1;
height = h1;
parent = *split;
*view = new View(View::ViewWindow,
renderer,
o,
x1, y1, w2, h2);
(*split)->child2 = *view;
(*view)->parent = *split;
(*view)->zoom = zoom;
}
View* View::remove(View* v)
{
int sign;
View *sibling;
if (v->parent->child1 == v)
{
sibling = v->parent->child2;
sign = -1;
}
else
{
sibling = v->parent->child1;
sign = 1;
}
sibling->parent = v->parent->parent;
if (v->parent->parent != nullptr)
{
if (v->parent->parent->child1 == v->parent)
v->parent->parent->child1 = sibling;
else
v->parent->parent->child2 = sibling;
}
v->walkTreeResize(sibling, sign);
delete(v->parent);
delete(v);
return sibling;
}
void View::reset()
{
x = 0.0f;
y = 0.0f;
width = 1.0f;
height = 1.0f;
parent = nullptr;
child1 = nullptr;
child2 = nullptr;
}
void View::drawBorder(int gWidth, int gHeight, const Color &color, float linewidth)
{
Rect r(x * gWidth, y * gHeight, width * gWidth - 1, height * gHeight - 1);
r.setColor(color);
r.setType(Rect::Type::BorderOnly);
r.setLineWidth(linewidth);
renderer->drawRectangle(r);
}

View File

@ -0,0 +1,68 @@
// view.h
//
// Copyright (C) 2001-2019, the Celestia Development Team
//
// 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
class Renderer;
class Observer;
class Color;
//namespace celestia
//{
class View
{
public:
enum Type
{
ViewWindow = 1,
HorizontalSplit = 2,
VerticalSplit = 3
};
View(Type, Renderer*, Observer*, float, float, float, float);
View() = delete;
~View() = default;
View(const View&) = delete;
View(View&&) = delete;
const View& operator=(const View&) = delete;
View& operator=(View&&) = delete;
void mapWindowToView(float, float, float&, float&) const;
void walkTreeResize(View*, int);
bool walkTreeResizeDelta(View*, float, bool);
void switchTo(int gWidth, int gHeight);
Observer* getObserver() const;
bool isRootView() const;
bool isSplittable(Type type) const;
void split(Type type, Observer *o, float splitPos, View **split, View **view);
void reset();
static View* remove(View*);
void drawBorder(int gWidth, int gHeight, const Color &color, float linewidth = 1.0f);
public:
Type type;
Renderer *renderer;
Observer *observer;
View *parent { nullptr };
View *child1 { nullptr };
View *child2 { nullptr };
float x;
float y;
float width;
float height;
uint64_t renderFlags { 0 };
int labelMode { 0 };
float zoom { 1.0f };
float alternateZoom { 1.0f };
};
//}

View File

@ -2684,7 +2684,7 @@ static void HandleCaptureImage(HWND hWnd)
// Get the dimensions of the current viewport
array<int,4> viewport;
appCore->getRenderer()->getScreenSize(viewport);
appCore->getRenderer()->getViewport(viewport);
bool success = false;

View File

@ -43,12 +43,30 @@ Color::Color(float r, float g, float b, float a)
}
Color::Color(unsigned char r, unsigned char g, unsigned char b)
Color::Color(unsigned char r, unsigned char g, unsigned char b) :
Color(r, g, b, 0xff)
{
}
Color::Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
{
c[Red] = r;
c[Green] = g;
c[Blue] = b;
c[Alpha] = 0xff;
c[Alpha] = a;
}
Color::Color(const Eigen::Vector3f &c) :
Color(c.x(), c.y(), c.z())
{
}
Color::Color(const Eigen::Vector4f &c) :
Color(c.x(), c.y(), c.z(), c.w())
{
}

View File

@ -22,9 +22,13 @@ class Color
Color(float, float, float);
Color(float, float, float, float);
Color(unsigned char, unsigned char, unsigned char);
Color(unsigned char, unsigned char, unsigned char, unsigned char);
Color(const Color&, float);
Color(const Eigen::Vector3f&);
Color(const Eigen::Vector4f&);
enum {
enum
{
Red = 0,
Green = 1,
Blue = 2,
@ -52,7 +56,6 @@ class Color
private:
static void buildX11ColorMap();
private:
unsigned char c[4];
typedef std::map<const std::string, Color> ColorMap;