Add view port effect for post processing

pull/852/head
Levin Li 2020-10-03 15:45:22 +08:00
parent 1f8cc6bb52
commit 17cd02b3cc
22 changed files with 675 additions and 44 deletions

View File

@ -0,0 +1,8 @@
varying vec2 texCoord;
uniform sampler2D tex;
void main(void)
{
gl_FragColor = texture2D(tex, texCoord);
}

View File

@ -0,0 +1,10 @@
attribute vec2 in_Position;
attribute vec2 in_TexCoord0;
varying vec2 texCoord;
void main(void)
{
gl_Position = vec4(in_Position.xy, 0.0, 1.0);
texCoord = in_TexCoord0.st;
}

View File

@ -0,0 +1,9 @@
varying vec2 texCoord;
varying float intensity;
uniform sampler2D tex;
void main(void)
{
gl_FragColor = vec4(texture2D(tex, texCoord).rgb * intensity, 1.0);
}

View File

@ -0,0 +1,16 @@
attribute vec2 in_Position;
attribute vec2 in_TexCoord0;
attribute float in_Intensity;
varying vec2 texCoord;
varying float intensity;
uniform float screenRatio;
void main(void)
{
float offset = 0.5 - screenRatio * 0.5;
gl_Position = vec4(in_Position.x * screenRatio, in_Position.y, 0.0, 1.0);
texCoord = vec2(in_TexCoord0.x * screenRatio + offset, in_TexCoord0.y);
intensity = in_Intensity;
}

View File

@ -69,6 +69,8 @@ set(CELENGINE_SOURCES
location.h
lodspheremesh.cpp
lodspheremesh.h
mapmanager.cpp
mapmanager.h
marker.cpp
marker.h
meshmanager.cpp
@ -168,6 +170,8 @@ set(CELENGINE_SOURCES
vecgl.h
vertexobject.cpp
vertexobject.h
viewporteffect.h
viewporteffect.cpp
virtualtex.cpp
virtualtex.h
visibleregion.cpp

View File

@ -138,6 +138,8 @@ FramebufferObject::generateFbo(unsigned int attachments)
{
// Create the FBO
glGenFramebuffers(1, &m_fboId);
GLint oldFboId;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFboId);
glBindFramebuffer(GL_FRAMEBUFFER, m_fboId);
#ifndef GL_ES
@ -151,7 +153,7 @@ FramebufferObject::generateFbo(unsigned int attachments)
m_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (m_status != GL_FRAMEBUFFER_COMPLETE)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, oldFboId);
cleanup();
return;
}
@ -171,7 +173,7 @@ FramebufferObject::generateFbo(unsigned int attachments)
m_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (m_status != GL_FRAMEBUFFER_COMPLETE)
{
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, oldFboId);
cleanup();
return;
}
@ -182,7 +184,7 @@ FramebufferObject::generateFbo(unsigned int attachments)
}
// Restore default frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, oldFboId);
}
// Delete all GL objects associated with this framebuffer object
@ -218,9 +220,8 @@ FramebufferObject::bind()
}
bool
FramebufferObject::unbind()
FramebufferObject::unbind(GLint oldfboId)
{
// Restore default frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindFramebuffer(GL_FRAMEBUFFER, oldfboId);
return true;
}

View File

@ -44,7 +44,7 @@ class FramebufferObject
GLuint depthTexture() const;
bool bind();
bool unbind();
bool unbind(GLint oldfboId);
private:
void generateColorTexture();

View File

@ -0,0 +1,196 @@
//
// mapmanager.cpp
//
// Copyright © 2020 Celestia Development Team. All rights reserved.
//
// 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 <celutil/debug.h>
#include <fstream>
#include "mapmanager.h"
using namespace std;
WarpMesh::WarpMesh(int nx, int ny, float *data) :
nx(nx),
ny(ny),
data(data)
{
}
WarpMesh::~WarpMesh()
{
delete data;
}
void WarpMesh::scopedDataForRendering(const function<void (float*, int)>& f) const
{
int step = 5 * 6;
int size = (nx - 1) * (ny - 1) * step * sizeof(float);
float *renderingData = new float[size];
for (int y = 0; y < ny - 1; y += 1)
{
for (int x = 0; x < nx - 1; x += 1)
{
float *destination = &renderingData[(y * (nx - 1) + x) * step];
float *source = &data[(y * nx + x) * 5];
// Top left triangle
memcpy(destination, source + 5 * nx, sizeof(float) * 5);
memcpy(destination + 5, source, sizeof(float) * 5);
memcpy(destination + 10, source + 5, sizeof(float) * 5);
// Bottom right triangle
memcpy(destination + 15, source + 5 * nx, sizeof(float) * 5);
memcpy(destination + 20, source + 5, sizeof(float) * 5);
memcpy(destination + 25, source + 5 * nx + 5, sizeof(float) * 5);
}
}
f(renderingData, size);
delete[] renderingData;
}
int WarpMesh::count() const
{
return 6 * (nx - 1) * (ny - 1);
}
bool WarpMesh::mapVertex(float x, float y, float* u, float* v) const
{
float minX = data[0];
float minY = data[1];
float maxX = data[(nx * ny - 1) * 5];
float maxY = data[(nx * ny - 1) * 5 + 1];
float stepX = (maxX - minX) / (nx - 1);
float stepY = (maxY - minY) / (ny - 1);
float locX = (x - minX) / stepX;
float locY = (y - minY) / stepY;
int floX = floorf(locX);
int floY = floorf(locY);
locX -= floX;
locY -= floY;
if (floX < 0 || floX >= nx - 1 || floY < 0 || floY >= ny - 1)
return false;
float p1x = data[(floY * nx + floX) * 5 + 2];
float p1y = data[(floY * nx + floX) * 5 + 3];
float p2x = data[(floY * nx + floX + 1) * 5 + 2];
float p2y = data[(floY * nx + floX + 1) * 5 + 3];
float p3x = data[(floY * nx + floX + nx) * 5 + 2];
float p3y = data[(floY * nx + floX + nx) * 5 + 3];
float p4x = data[(floY * nx + floX + nx + 1) * 5 + 2];
float p4y = data[(floY * nx + floX + nx + 1) * 5 + 3];
if (locX + locY <= 1)
{
// the top left part triangle
*u = p1x + locX * (p2x - p1x) + locY * (p3x - p1x);
*v = p1y + locX * (p2y - p1y) + locY * (p3y - p1y);
}
else
{
// the bottom right triangle
locX -= 1;
locY -= 1;
*u = p4x + locX * (p4x - p3x) + locY * (p4x - p2x);
*v = p4y + locX * (p4y - p3y) + locY * (p4y - p2y);
}
// Texture coordinate is [0, 1], normalize to [-1, 1]
*u = (*u) * 2 - 1;
*v = (*v) * 2 - 1;
return true;
}
WarpMeshManager* GetWarpMeshManager()
{
static WarpMeshManager* warpMeshManager = nullptr;
if (warpMeshManager == nullptr)
warpMeshManager = new WarpMeshManager("warp");
return warpMeshManager;
}
static string resolveWildcard(const string& filename)
{
string base(filename, 0, filename.length() - 1);
string mapfile = base + "map";
ifstream in(mapfile);
if (in.good())
return mapfile;
return {};
}
fs::path WarpMeshInfo::resolve(const fs::path& baseDir)
{
bool wildcard = false;
if (!source.empty() && source.at(source.length() - 1) == '*')
wildcard = true;
fs::path filename = baseDir / source;
if (wildcard)
{
string matched = resolveWildcard(filename.string());
if (matched.empty())
return filename; // . . . for lack of any better way to handle it.
else
return matched;
}
return filename;
}
WarpMesh* WarpMeshInfo::load(const fs::path& name)
{
#define MESHTYPE_RECT 2
ifstream f(name.string());
if (!f.good())
return nullptr;
int type, nx, ny;
if (!(f >> type))
{
DPRINTF(LOG_LEVEL_ERROR, "Failed to read mesh header\n");
return nullptr;
}
if (type != MESHTYPE_RECT)
{
DPRINTF(LOG_LEVEL_ERROR, "Unsupported mesh type found: %d\n", type);
return nullptr;
}
if (!(f >> nx >> ny))
{
DPRINTF(LOG_LEVEL_ERROR, "Failed to read mesh header\n");
return nullptr;
}
if (nx < 2 || ny < 2)
{
DPRINTF(LOG_LEVEL_ERROR, "Row and column numbers should be larger than 2\n");
return nullptr;
}
float *data = new float[nx * ny * 5];
for (int y = 0; y < ny; y += 1)
{
for (int x = 0; x < nx; x += 1)
{
float *base = &data[(y * nx + x) * 5];
if (!(f >> base[0] >> base[1] >> base[2] >> base[3] >> base[4]))
{
DPRINTF(LOG_LEVEL_ERROR, "Failed to read mesh data\n");
delete[] data;
return nullptr;
}
}
}
DPRINTF(LOG_LEVEL_INFO, "Read a mesh of %d * %d\n", nx, ny);
return new WarpMesh(nx, ny, data);
}

View File

@ -0,0 +1,57 @@
//
// mapmanager.h
//
// Copyright © 2020 Celestia Development Team. All rights reserved.
//
// 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 <string>
#include <map>
#include <functional>
#include <celutil/resmanager.h>
// File format for data used to warp an image, for
// detail, see http://paulbourke.net/dataformats/meshwarp/
class WarpMesh
{
public:
WarpMesh(int nx, int ny, float* data);
~WarpMesh();
// Map data to triangle vertices used for drawing
void scopedDataForRendering(const std::function<void(float*, int)>&) const;
int count() const; // Number of vertices
// Convert a vertex coordinate to texture coordinate
bool mapVertex(float x, float y, float* u, float* v) const;
private:
int nx;
int ny;
float* data;
};
class WarpMeshInfo : public ResourceInfo<WarpMesh>
{
public:
std::string source;
WarpMeshInfo(const std::string& source) : source(source) {};
fs::path resolve(const fs::path&) override;
WarpMesh* load(const fs::path&) override;
};
inline bool operator<(const WarpMeshInfo& wi0, const WarpMeshInfo& wi1)
{
return wi0.source < wi1.source;
}
typedef ResourceManager<WarpMeshInfo> WarpMeshManager;
WarpMeshManager* GetWarpMeshManager();

View File

@ -910,6 +910,8 @@ void renderGeometryShadow_GLSL(Geometry* geometry,
if (prog == nullptr)
return;
GLint oldFboId;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFboId);
shadowFbo->bind();
glViewport(0, 0, shadowFbo->width(), shadowFbo->height());
@ -939,5 +941,5 @@ void renderGeometryShadow_GLSL(Geometry* geometry,
// Re-enable the color buffer
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glCullFace(GL_BACK);
shadowFbo->unbind();
shadowFbo->unbind(oldFboId);
}

View File

@ -3213,6 +3213,10 @@ ShaderManager::buildProgram(const ShaderProperties& props)
CelestiaGLProgram::ColorAttributeIndex,
"in_Color");
glBindAttribLocation(prog->getID(),
CelestiaGLProgram::IntensityAttributeIndex,
"in_Intensity");
if (props.texUsage & ShaderProperties::NormalTexture)
{
glBindAttribLocation(prog->getID(),
@ -3313,6 +3317,10 @@ ShaderManager::buildProgram(const std::string& vs, const std::string& fs)
CelestiaGLProgram::PointSizeAttributeIndex,
"in_PointSize");
glBindAttribLocation(prog->getID(),
CelestiaGLProgram::IntensityAttributeIndex,
"in_Intensity");
status = prog->link();
}

View File

@ -183,6 +183,7 @@ class CelestiaGLProgram
TangentAttributeIndex = 6,
PointSizeAttributeIndex = 7,
ColorAttributeIndex = 8,
IntensityAttributeIndex = 9,
};
public:

View File

@ -0,0 +1,161 @@
//
// viewporteffect.cpp
//
// Copyright © 2020 Celestia Development Team. All rights reserved.
//
// 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 "viewporteffect.h"
#include "framebuffer.h"
#include "render.h"
#include "shadermanager.h"
#include "mapmanager.h"
bool ViewportEffect::preprocess(Renderer* renderer, FramebufferObject* fbo)
{
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &oldFboId);
return fbo->bind();
}
bool ViewportEffect::prerender(Renderer* renderer, FramebufferObject* fbo)
{
if (!fbo->unbind(oldFboId))
return false;
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
return true;
}
bool ViewportEffect::distortXY(float &x, float &y)
{
return true;
}
PassthroughViewportEffect::PassthroughViewportEffect() :
ViewportEffect(),
vo(GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW)
{
}
bool PassthroughViewportEffect::prerender(Renderer* renderer, FramebufferObject* fbo)
{
if (!ViewportEffect::prerender(renderer, fbo))
return false;
renderer->disableDepthTest();
return true;
}
bool PassthroughViewportEffect::render(Renderer* renderer, FramebufferObject* fbo, int width, int height)
{
CelestiaGLProgram *prog = renderer->getShaderManager().getShader("passthrough");
if (prog == nullptr)
return false;
vo.bind();
if (!vo.initialized())
initializeVO(vo);
prog->use();
prog->samplerParam("tex") = 0;
glBindTexture(GL_TEXTURE_2D, fbo->colorTexture());
draw(vo);
glBindTexture(GL_TEXTURE_2D, 0);
vo.unbind();
return true;
}
void PassthroughViewportEffect::initializeVO(celgl::VertexObject& vo)
{
static float quadVertices[] = {
// positions // texCoords
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
vo.allocate(sizeof(quadVertices), quadVertices);
vo.setVertices(2, GL_FLOAT, false, 4 * sizeof(float), 0);
vo.setTextureCoords(2, GL_FLOAT, false, 4 * sizeof(float), 2 * sizeof(float));
}
void PassthroughViewportEffect::draw(celgl::VertexObject& vo)
{
vo.draw(GL_TRIANGLES, 6);
}
WarpMeshViewportEffect::WarpMeshViewportEffect(WarpMesh *mesh) :
ViewportEffect(),
vo(GL_ARRAY_BUFFER, 0, GL_STATIC_DRAW),
mesh(mesh)
{
}
bool WarpMeshViewportEffect::prerender(Renderer* renderer, FramebufferObject* fbo)
{
if (mesh == nullptr)
return false;
if (!ViewportEffect::prerender(renderer, fbo))
return false;
renderer->disableDepthTest();
return true;
}
bool WarpMeshViewportEffect::render(Renderer* renderer, FramebufferObject* fbo, int width, int height)
{
CelestiaGLProgram *prog = renderer->getShaderManager().getShader("warpmesh");
if (prog == nullptr)
return false;
vo.bind();
if (!vo.initialized())
initializeVO(vo);
prog->use();
prog->samplerParam("tex") = 0;
prog->floatParam("screenRatio") = (float)height / width;
glBindTexture(GL_TEXTURE_2D, fbo->colorTexture());
draw(vo);
glBindTexture(GL_TEXTURE_2D, 0);
vo.unbind();
return true;
}
void WarpMeshViewportEffect::initializeVO(celgl::VertexObject& vo)
{
mesh->scopedDataForRendering([&vo](float *data, int size){
vo.allocate(size, data);
vo.setVertices(2, GL_FLOAT, false, 5 * sizeof(float), 0);
vo.setTextureCoords(2, GL_FLOAT, false, 5 * sizeof(float), 2 * sizeof(float));
vo.setVertexAttribArray(CelestiaGLProgram::IntensityAttributeIndex, 1, GL_FLOAT, false, 5 * sizeof(float), 4 * sizeof(float));
});
}
void WarpMeshViewportEffect::draw(celgl::VertexObject& vo)
{
vo.draw(GL_TRIANGLES, mesh->count());
}
bool WarpMeshViewportEffect::distortXY(float &x, float &y)
{
if (mesh == nullptr)
return false;
float u;
float v;
if (!mesh->mapVertex(x * 2, y * 2, &u, &v))
return false;
x = u / 2;
y = v / 2;
return true;
}

View File

@ -0,0 +1,68 @@
//
// viewporteffect.h
//
// Copyright © 2020 Celestia Development Team. All rights reserved.
//
// 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 <string>
#include <celengine/glsupport.h>
#include <celengine/vertexobject.h>
class FramebufferObject;
class Renderer;
class CelestiaGLProgram;
class WarpMesh;
class ViewportEffect
{
public:
virtual ~ViewportEffect() = default;
virtual bool preprocess(Renderer*, FramebufferObject*);
virtual bool prerender(Renderer*, FramebufferObject*);
virtual bool render(Renderer*, FramebufferObject*, int width, int height) = 0;
virtual bool distortXY(float& x, float& y);
private:
GLint oldFboId;
};
class PassthroughViewportEffect : public ViewportEffect
{
public:
PassthroughViewportEffect();
~PassthroughViewportEffect() override = default;
bool prerender(Renderer*, FramebufferObject* fbo) override;
bool render(Renderer*, FramebufferObject*, int width, int height) override;
private:
celgl::VertexObject vo;
void initializeVO(celgl::VertexObject&);
void draw(celgl::VertexObject&);
};
class WarpMeshViewportEffect : public ViewportEffect
{
public:
WarpMeshViewportEffect(WarpMesh *mesh);
~WarpMeshViewportEffect() override = default;
bool prerender(Renderer*, FramebufferObject* fbo) override;
bool render(Renderer*, FramebufferObject*, int width, int height) override;
bool distortXY(float& x, float& y) override;
private:
celgl::VertexObject vo;
WarpMesh *mesh;
void initializeVO(celgl::VertexObject&);
void draw(celgl::VertexObject&);
};

View File

@ -30,6 +30,7 @@
#include <celengine/axisarrow.h>
#include <celengine/planetgrid.h>
#include <celengine/visibleregion.h>
#include <celengine/framebuffer.h>
#include <celmath/geomutil.h>
#include <celutil/color.h>
#include <celutil/filetype.h>
@ -50,6 +51,7 @@
#include <ctime>
#include <set>
#include <celengine/rectangle.h>
#include <celengine/mapmanager.h>
#ifdef CELX
#include <celephem/scriptobject.h>
@ -424,8 +426,11 @@ void CelestiaCore::mouseButtonUp(float x, float y, int button)
(*activeView)->mapWindowToView((float) x / (float) width,
(float) y / (float) height,
pickX, pickY);
Vector3f pickRay =
sim->getActiveObserver()->getPickRay(pickX * aspectRatio, pickY);
pickX *= aspectRatio;
if (isViewportEffectUsed)
viewportEffect->distortXY(pickX, pickY);
Vector3f pickRay = sim->getActiveObserver()->getPickRay(pickX, pickY);
Selection oldSel = sim->getSelection();
Selection newSel = sim->pickObject(pickRay, renderer->getRenderFlags(), pickTolerance);
@ -441,8 +446,11 @@ void CelestiaCore::mouseButtonUp(float x, float y, int button)
(*activeView)->mapWindowToView((float) x / (float) width,
(float) y / (float) height,
pickX, pickY);
Vector3f pickRay =
sim->getActiveObserver()->getPickRay(pickX * aspectRatio, pickY);
pickX *= aspectRatio;
if (isViewportEffectUsed)
viewportEffect->distortXY(pickX, pickY);
Vector3f pickRay = sim->getActiveObserver()->getPickRay(pickX, pickY);
Selection sel = sim->pickObject(pickRay, renderer->getRenderFlags(), pickTolerance);
if (!sel.empty())
@ -2057,30 +2065,13 @@ void CelestiaCore::draw()
return;
viewChanged = false;
if (views.size() == 1)
{
// 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 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
// Render each view
for (const auto view : views)
draw(view);
// Reset to render to the main window
if (views.size() > 1)
renderer->setRenderRegion(0, 0, width, height, false);
sim->render(*renderer);
}
else
{
for (const auto view : views)
{
if (view->type == View::ViewWindow)
{
view->switchTo(width, height);
sim->render(*renderer, *view->observer);
}
}
renderer->setRenderRegion(0, 0, width, height, false);
}
bool toggleAA = renderer->isMSAAEnabled();
if (toggleAA && (renderer->getRenderFlags() & Renderer::ShowCloudMaps))
@ -2143,6 +2134,47 @@ void CelestiaCore::resize(GLsizei w, GLsizei h)
return;
}
void CelestiaCore::draw(View* view)
{
if (view->type != View::ViewWindow) return;
bool viewportEffectUsed = false;
FramebufferObject *fbo = nullptr;
if (viewportEffect != nullptr)
{
// create/update FBO for viewport effect
view->updateFBO(width, height);
fbo = view->getFBO();
}
bool process = fbo != nullptr && viewportEffect->preprocess(renderer, fbo);
int x = view->x * width;
int y = view->y * height;
int viewWidth = view->width * width;
int viewHeight = view->height * height;
// If we need to process, we draw to the FBO which starts at point zero
renderer->setRenderRegion(process ? 0 : x, process ? 0 : y, viewWidth, viewHeight, !view->isRootView());
if (view->isRootView())
sim->render(*renderer);
else
sim->render(*renderer, *view->observer);
// Viewport need to be reset to start from (x,y) instead of point zero
if (process && (x != 0 || y != 0))
renderer->setRenderRegion(x, y, viewWidth, viewHeight);
if (process && viewportEffect->prerender(renderer, fbo))
{
if (viewportEffect->render(renderer, fbo, viewWidth, viewHeight))
viewportEffectUsed = true;
else
DPRINTF(LOG_LEVEL_ERROR, "Unable to render viewport effect.\n");
}
isViewportEffectUsed = viewportEffectUsed;
}
void CelestiaCore::setSafeAreaInsets(int left, int top, int right, int bottom)
{
@ -3781,6 +3813,30 @@ bool CelestiaCore::initSimulation(const fs::path& configFileName,
}
}
if (!config->viewportEffect.empty() && config->viewportEffect != "none")
{
if (config->viewportEffect == "passthrough")
viewportEffect = unique_ptr<ViewportEffect>(new PassthroughViewportEffect);
else if (config->viewportEffect == "warpmesh")
{
if (config->warpMeshFile.empty())
{
DPRINTF(LOG_LEVEL_WARNING, "No warp mesh file specified for this effect\n");
}
else
{
WarpMeshManager *manager = GetWarpMeshManager();
WarpMesh *mesh = manager->find(manager->getHandle(WarpMeshInfo(config->warpMeshFile)));
if (mesh != nullptr)
viewportEffect = unique_ptr<ViewportEffect>(new WarpMeshViewportEffect(mesh));
else
DPRINTF(LOG_LEVEL_WARNING, "Failed to read warp mesh file %s\n", config->warpMeshFile);
}
}
else
DPRINTF(LOG_LEVEL_WARNING, "Unknown viewport effect %s\n", config->viewportEffect);
}
sim = new Simulation(universe);
if ((renderer->getRenderFlags() & Renderer::ShowAutoMag) == 0)
{

View File

@ -21,6 +21,7 @@
#include <celengine/render.h>
#include <celengine/simulation.h>
#include <celengine/overlayimage.h>
#include <celengine/viewporteffect.h>
#include "configfile.h"
#include "favorites.h"
#include "destination.h"
@ -210,6 +211,7 @@ class CelestiaCore // : public Watchable<CelestiaCore>
void joystickButton(int button, bool down);
void resize(GLsizei w, GLsizei h);
void draw();
void draw(View*);
void tick();
Simulation* getSimulation() const;
@ -465,6 +467,9 @@ class CelestiaCore // : public Watchable<CelestiaCore>
int screenDpi{ 96 };
int distanceToScreen{ 400 };
unique_ptr<ViewportEffect> viewportEffect { nullptr };
bool isViewportEffectUsed { false };
struct EdgeInsets
{
int left;

View File

@ -93,6 +93,8 @@ CelestiaConfig* ReadCelestiaConfig(const fs::path& filename, CelestiaConfig *con
configParams->getString("TitleFont", config->titleFont);
configParams->getPath("LogoTexture", config->logoTextureFile);
configParams->getString("Cursor", config->cursor);
configParams->getString("ViewportEffect", config->viewportEffect);
configParams->getString("WarpMeshFile", config->warpMeshFile);
float maxDist = 1.0;
configParams->getNumber("SolarSystemMaxDistance", maxDist);

View File

@ -78,6 +78,9 @@ public:
float SolarSystemMaxDistance;
unsigned ShadowMapSize;
std::string viewportEffect;
std::string warpMeshFile;
};
CelestiaConfig* ReadCelestiaConfig(const fs::path& filename, CelestiaConfig* config = nullptr);

View File

@ -9,6 +9,7 @@
#include <celengine/rectangle.h>
#include <celengine/render.h>
#include <celengine/framebuffer.h>
#include <celutil/color.h>
#include "view.h"
@ -150,14 +151,6 @@ 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.
@ -254,6 +247,7 @@ void View::reset()
parent = nullptr;
child1 = nullptr;
child2 = nullptr;
fbo = nullptr;
}
void View::drawBorder(int gWidth, int gHeight, const Color &color, float linewidth)
@ -264,3 +258,25 @@ void View::drawBorder(int gWidth, int gHeight, const Color &color, float linewid
r.setLineWidth(linewidth);
renderer->drawRectangle(r, renderer->getOrthoProjectionMatrix());
}
void View::updateFBO(int gWidth, int gHeight)
{
int newWidth = width * gWidth;
int newHeight = height * gHeight;
if (fbo && fbo.get()->width() == newWidth && fbo.get()->height() == newHeight)
return;
// recreate FBO when FBO not exisits or on size change
fbo = unique_ptr<FramebufferObject>(new FramebufferObject(newWidth, newHeight,
FramebufferObject::ColorAttachment | FramebufferObject::DepthAttachment));
if (!fbo->isValid())
{
DPRINTF(LOG_LEVEL_ERROR, "Error creating view FBO.\n");
fbo = nullptr;
}
}
FramebufferObject *View::getFBO() const
{
return fbo.get();
}

View File

@ -38,7 +38,6 @@ class View
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;
@ -46,6 +45,8 @@ class View
void reset();
static View* remove(View*);
void drawBorder(int gWidth, int gHeight, const Color &color, float linewidth = 1.0f);
void updateFBO(int gWidth, int gHeight);
FramebufferObject *getFBO() const;
public:
Type type;
@ -63,6 +64,9 @@ class View
int labelMode { 0 };
float zoom { 1.0f };
float alternateZoom { 1.0f };
private:
std::unique_ptr<FramebufferObject> fbo;
};
//}

View File

@ -37,6 +37,7 @@ static const char CelestiaModelExt[] = ".cmod";
static const char CelestiaParticleSystemExt[] = ".cpart";
static const char CelestiaXYZTrajectoryExt[] = ".xyz";
static const char CelestiaXYZVTrajectoryExt[] = ".xyzv";
static const char Content_WarpMeshExt[] = ".map";
ContentType DetermineFileType(const fs::path& filename)
{
@ -83,6 +84,8 @@ ContentType DetermineFileType(const fs::path& filename)
return Content_CelestiaXYZTrajectory;
if (compareIgnoringCase(CelestiaXYZVTrajectoryExt, ext) == 0)
return Content_CelestiaXYZVTrajectory;
if (compareIgnoringCase(Content_WarpMeshExt, ext) == 0)
return Content_WarpMesh;
else
return Content_Unknown;
}

View File

@ -35,6 +35,7 @@ enum ContentType
Content_CelestiaXYZTrajectory = 18,
Content_CelestiaXYZVTrajectory = 19,
Content_CelestiaParticleSystem = 20,
Content_WarpMesh = 21,
Content_Unknown = -1,
};