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 controlpull/444/head
parent
6e44de22f1
commit
e3baaad767
|
@ -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
|
||||
|
|
|
@ -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
|
||||
//
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 };
|
||||
};
|
|
@ -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,16 +528,42 @@ bool AssociativeArray::getRotation(const string& key, Eigen::Quaternionf& val) c
|
|||
|
||||
bool AssociativeArray::getColor(const string& key, Color& val) const
|
||||
{
|
||||
Vector3d vecVal;
|
||||
|
||||
if (!getVector(key, vecVal))
|
||||
return false;
|
||||
|
||||
val = Color((float) vecVal.x(), (float) vecVal.y(), (float) vecVal.z());
|
||||
|
||||
Vector4d vec4;
|
||||
if (getVector(key, vec4))
|
||||
{
|
||||
Vector4f vec4f = vec4.cast<float>();
|
||||
val = Color(vec4f);
|
||||
return true;
|
||||
}
|
||||
|
||||
Vector3d vec3;
|
||||
if (getVector(key, vec3))
|
||||
{
|
||||
Vector3f vec3f = vec3.cast<float>();
|
||||
val = Color(vec3f);
|
||||
return true;
|
||||
}
|
||||
|
||||
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 false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Retrieves a numeric quantity scaled to an associated angle unit.
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 };
|
||||
};
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 };
|
||||
|
||||
|
|
|
@ -24,6 +24,8 @@ set(CELESTIA_SOURCES
|
|||
scriptmenu.h
|
||||
url.cpp
|
||||
url.h
|
||||
view.cpp
|
||||
view.h
|
||||
)
|
||||
|
||||
set(CELX_SOURCES
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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 )
|
||||
|
@ -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
|
||||
// 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);
|
||||
}
|
||||
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);
|
||||
|
@ -2643,53 +2445,30 @@ void CelestiaCore::setActiveView(View* v)
|
|||
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);
|
||||
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);
|
||||
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,
|
||||
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,
|
||||
color,
|
||||
Overlay::RectType::Outlined);
|
||||
overlay->rect(r);
|
||||
glTranslatef((float) ((width - movieWidth) / 2),
|
||||
(float) ((height + movieHeight) / 2 + 2), 0.0f);
|
||||
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
|
||||
|
@ -4214,9 +3914,11 @@ bool CelestiaCore::initSimulation(const fs::path& configFileName,
|
|||
|
||||
sim = new Simulation(universe);
|
||||
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();
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -773,33 +773,51 @@ 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);
|
||||
|
||||
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->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))
|
||||
{
|
||||
int f;
|
||||
if(!paramList->getNumber("fitscreen", f))
|
||||
fitscreen = false;
|
||||
else
|
||||
// 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")
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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 };
|
||||
};
|
||||
|
||||
//}
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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())
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue