Render the world in its own framebuffer
This commit is contained in:
parent
fe4cc19618
commit
fe99ec6966
@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
"effectParameters" : {},
|
|
||||||
"effectTextures" : {},
|
|
||||||
|
|
||||||
"effectShaders" : {
|
|
||||||
"vertex" : "default.vert",
|
|
||||||
"fragment" : "default.frag"
|
|
||||||
}
|
|
||||||
}
|
|
11
assets/opensb/rendering/effects/interface.config
Normal file
11
assets/opensb/rendering/effects/interface.config
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
{
|
||||||
|
"blitFrameBuffer" : "world",
|
||||||
|
|
||||||
|
"effectParameters" : {},
|
||||||
|
"effectTextures" : {},
|
||||||
|
|
||||||
|
"effectShaders" : {
|
||||||
|
"vertex" : "interface.vert",
|
||||||
|
"fragment" : "interface.frag"
|
||||||
|
}
|
||||||
|
}
|
@ -1,4 +1,6 @@
|
|||||||
{
|
{
|
||||||
|
"frameBuffer" : "world",
|
||||||
|
|
||||||
"effectParameters" : {
|
"effectParameters" : {
|
||||||
"lightMapEnabled" : {
|
"lightMapEnabled" : {
|
||||||
"type" : "bool",
|
"type" : "bool",
|
5
assets/opensb/rendering/opengl20.config.patch
Normal file
5
assets/opensb/rendering/opengl20.config.patch
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"frameBuffers" : {
|
||||||
|
"world" : {}
|
||||||
|
}
|
||||||
|
}
|
@ -130,6 +130,8 @@ public:
|
|||||||
virtual String rendererId() const = 0;
|
virtual String rendererId() const = 0;
|
||||||
virtual Vec2U screenSize() const = 0;
|
virtual Vec2U screenSize() const = 0;
|
||||||
|
|
||||||
|
virtual void loadConfig(Json const& config) = 0;
|
||||||
|
|
||||||
// The actual shaders used by this renderer will be in a default no effects
|
// The actual shaders used by this renderer will be in a default no effects
|
||||||
// state when constructed, but can be overridden here. This config will be
|
// state when constructed, but can be overridden here. This config will be
|
||||||
// specific to each type of renderer, so it will be necessary to key the
|
// specific to each type of renderer, so it will be necessary to key the
|
||||||
|
@ -105,6 +105,7 @@ OpenGl20Renderer::~OpenGl20Renderer() {
|
|||||||
for (auto& effect : m_effects)
|
for (auto& effect : m_effects)
|
||||||
glDeleteProgram(effect.second.program);
|
glDeleteProgram(effect.second.program);
|
||||||
|
|
||||||
|
m_frameBuffers.clear();
|
||||||
logGlErrorSummary("OpenGL errors during shutdown");
|
logGlErrorSummary("OpenGL errors during shutdown");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,6 +117,38 @@ Vec2U OpenGl20Renderer::screenSize() const {
|
|||||||
return m_screenSize;
|
return m_screenSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
OpenGl20Renderer::GlFrameBuffer::GlFrameBuffer(Json const& fbConfig) : config(fbConfig) {
|
||||||
|
texture = createGlTexture(Image(), TextureAddressing::Clamp, TextureFiltering::Nearest);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture->glTextureId());
|
||||||
|
|
||||||
|
Vec2U size = jsonToVec2U(config.getArray("size", { 256, 256 }));
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size[0] , size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
|
||||||
|
glGenFramebuffers(1, &id);
|
||||||
|
if (!id)
|
||||||
|
throw RendererException("Failed to create OpenGL framebuffer");
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, id);
|
||||||
|
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture->glTextureId(), 0);
|
||||||
|
|
||||||
|
auto framebufferStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||||
|
if (framebufferStatus != GL_FRAMEBUFFER_COMPLETE)
|
||||||
|
throw RendererException("OpenGL framebuffer is not complete!");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
OpenGl20Renderer::GlFrameBuffer::~GlFrameBuffer() {
|
||||||
|
glDeleteFramebuffers(1, &id);
|
||||||
|
texture.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGl20Renderer::loadConfig(Json const& config) {
|
||||||
|
m_frameBuffers.clear();
|
||||||
|
|
||||||
|
for (auto& pair : config.getObject("frameBuffers", {}))
|
||||||
|
m_frameBuffers[pair.first] = make_ref<GlFrameBuffer>(pair.second);
|
||||||
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::loadEffectConfig(String const& name, Json const& effectConfig, StringMap<String> const& shaders) {
|
void OpenGl20Renderer::loadEffectConfig(String const& name, Json const& effectConfig, StringMap<String> const& shaders) {
|
||||||
if (m_effects.contains(name)) {
|
if (m_effects.contains(name)) {
|
||||||
Logger::warn("OpenGL effect {} already exists", name);
|
Logger::warn("OpenGL effect {} already exists", name);
|
||||||
@ -303,6 +336,18 @@ bool OpenGl20Renderer::switchEffectConfig(String const& name) {
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
Effect& effect = find->second;
|
Effect& effect = find->second;
|
||||||
|
if (m_currentEffect == &effect)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (auto blitFrameBufferId = effect.config.optString("blitFrameBuffer"))
|
||||||
|
blitGlFrameBuffer(getGlFrameBuffer(*blitFrameBufferId));
|
||||||
|
|
||||||
|
if (auto frameBufferId = effect.config.optString("frameBuffer"))
|
||||||
|
switchGlFrameBuffer(getGlFrameBuffer(*frameBufferId));
|
||||||
|
else {
|
||||||
|
m_currentFrameBuffer.reset();
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
}
|
||||||
|
|
||||||
glUseProgram(m_program = effect.program);
|
glUseProgram(m_program = effect.program);
|
||||||
setupGlUniforms(effect);
|
setupGlUniforms(effect);
|
||||||
@ -387,11 +432,24 @@ void OpenGl20Renderer::setScreenSize(Vec2U screenSize) {
|
|||||||
m_screenSize = screenSize;
|
m_screenSize = screenSize;
|
||||||
glViewport(0, 0, m_screenSize[0], m_screenSize[1]);
|
glViewport(0, 0, m_screenSize[0], m_screenSize[1]);
|
||||||
glUniform2f(m_screenSizeUniform, m_screenSize[0], m_screenSize[1]);
|
glUniform2f(m_screenSizeUniform, m_screenSize[0], m_screenSize[1]);
|
||||||
|
|
||||||
|
for (auto& frameBuffer : m_frameBuffers) {
|
||||||
|
glBindTexture(GL_TEXTURE_2D, frameBuffer.second->texture->glTextureId());
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, m_screenSize[0], m_screenSize[1], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::startFrame() {
|
void OpenGl20Renderer::startFrame() {
|
||||||
if (m_scissorRect)
|
if (m_scissorRect)
|
||||||
glDisable(GL_SCISSOR_TEST);
|
glDisable(GL_SCISSOR_TEST);
|
||||||
|
|
||||||
|
for (auto& frameBuffer : m_frameBuffers) {
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer.second->id);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
frameBuffer.second->blitted = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
@ -417,6 +475,9 @@ void OpenGl20Renderer::finishFrame() {
|
|||||||
return false;
|
return false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Blit if another shader hasn't
|
||||||
|
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||||
|
|
||||||
if (DebugEnabled)
|
if (DebugEnabled)
|
||||||
logGlErrorSummary("OpenGL errors this frame");
|
logGlErrorSummary("OpenGL errors this frame");
|
||||||
}
|
}
|
||||||
@ -456,17 +517,20 @@ void OpenGl20Renderer::GlTextureAtlasSet::copyAtlasPixels(
|
|||||||
glBindTexture(GL_TEXTURE_2D, glTexture);
|
glBindTexture(GL_TEXTURE_2D, glTexture);
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
if (image.pixelFormat() == PixelFormat::RGB24) {
|
GLenum format;
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, bottomLeft[0], bottomLeft[1], image.width(), image.height(), GL_RGB, GL_UNSIGNED_BYTE, image.data());
|
auto pixelFormat = image.pixelFormat();
|
||||||
} else if (image.pixelFormat() == PixelFormat::RGBA32) {
|
if (pixelFormat == PixelFormat::RGB24)
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, bottomLeft[0], bottomLeft[1], image.width(), image.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.data());
|
format = GL_RGB;
|
||||||
} else if (image.pixelFormat() == PixelFormat::BGR24) {
|
else if (pixelFormat == PixelFormat::RGBA32)
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, bottomLeft[0], bottomLeft[1], image.width(), image.height(), GL_BGR, GL_UNSIGNED_BYTE, image.data());
|
format = GL_RGBA;
|
||||||
} else if (image.pixelFormat() == PixelFormat::BGRA32) {
|
else if (pixelFormat == PixelFormat::BGR24)
|
||||||
glTexSubImage2D(GL_TEXTURE_2D, 0, bottomLeft[0], bottomLeft[1], image.width(), image.height(), GL_BGRA, GL_UNSIGNED_BYTE, image.data());
|
format = GL_BGR;
|
||||||
} else {
|
else if (pixelFormat == PixelFormat::BGRA32)
|
||||||
|
format = GL_BGRA;
|
||||||
|
else
|
||||||
throw RendererException("Unsupported texture format in OpenGL20Renderer::TextureGroup::copyAtlasPixels");
|
throw RendererException("Unsupported texture format in OpenGL20Renderer::TextureGroup::copyAtlasPixels");
|
||||||
}
|
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, bottomLeft[0], bottomLeft[1], image.width(), image.height(), format, GL_UNSIGNED_BYTE, image.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
OpenGl20Renderer::GlTextureGroup::GlTextureGroup(unsigned atlasNumCells)
|
OpenGl20Renderer::GlTextureGroup::GlTextureGroup(unsigned atlasNumCells)
|
||||||
@ -608,7 +672,7 @@ void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive>& primitives) {
|
|||||||
glBufferData(GL_ARRAY_BUFFER, accumulationBuffer.size(), accumulationBuffer.ptr(), GL_STREAM_DRAW);
|
glBufferData(GL_ARRAY_BUFFER, accumulationBuffer.size(), accumulationBuffer.ptr(), GL_STREAM_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
vertexBuffers.append(vb);
|
vertexBuffers.emplace_back(move(vb));
|
||||||
|
|
||||||
currentTextures.clear();
|
currentTextures.clear();
|
||||||
currentTextureSizes.clear();
|
currentTextureSizes.clear();
|
||||||
@ -654,9 +718,10 @@ void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive>& primitives) {
|
|||||||
++currentVertexCount;
|
++currentVertexCount;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
float textureIndex = 0.0f;
|
||||||
|
Vec2F textureOffset = {};
|
||||||
|
Texture* lastTexture = nullptr;
|
||||||
for (auto& primitive : primitives) {
|
for (auto& primitive : primitives) {
|
||||||
float textureIndex;
|
|
||||||
Vec2F textureOffset;
|
|
||||||
if (auto tri = primitive.ptr<RenderTriangle>()) {
|
if (auto tri = primitive.ptr<RenderTriangle>()) {
|
||||||
tie(textureIndex, textureOffset) = addCurrentTexture(move(tri->texture));
|
tie(textureIndex, textureOffset) = addCurrentTexture(move(tri->texture));
|
||||||
|
|
||||||
@ -678,6 +743,7 @@ void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive>& primitives) {
|
|||||||
} else if (auto poly = primitive.ptr<RenderPoly>()) {
|
} else if (auto poly = primitive.ptr<RenderPoly>()) {
|
||||||
if (poly->vertexes.size() > 2) {
|
if (poly->vertexes.size() > 2) {
|
||||||
tie(textureIndex, textureOffset) = addCurrentTexture(move(poly->texture));
|
tie(textureIndex, textureOffset) = addCurrentTexture(move(poly->texture));
|
||||||
|
|
||||||
for (size_t i = 1; i < poly->vertexes.size() - 1; ++i) {
|
for (size_t i = 1; i < poly->vertexes.size() - 1; ++i) {
|
||||||
appendBufferVertex(poly->vertexes[0], textureIndex, textureOffset);
|
appendBufferVertex(poly->vertexes[0], textureIndex, textureOffset);
|
||||||
appendBufferVertex(poly->vertexes[i], textureIndex, textureOffset);
|
appendBufferVertex(poly->vertexes[i], textureIndex, textureOffset);
|
||||||
@ -723,17 +789,20 @@ bool OpenGl20Renderer::logGlErrorSummary(String prefix) {
|
|||||||
|
|
||||||
void OpenGl20Renderer::uploadTextureImage(PixelFormat pixelFormat, Vec2U size, uint8_t const* data) {
|
void OpenGl20Renderer::uploadTextureImage(PixelFormat pixelFormat, Vec2U size, uint8_t const* data) {
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
if (pixelFormat == PixelFormat::RGB24) {
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size[0], size[1], 0, GL_RGB, GL_UNSIGNED_BYTE, data);
|
GLenum format;
|
||||||
} else if (pixelFormat == PixelFormat::RGBA32) {
|
if (pixelFormat == PixelFormat::RGB24)
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size[0], size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
format = GL_RGB;
|
||||||
} else if (pixelFormat == PixelFormat::BGR24) {
|
else if (pixelFormat == PixelFormat::RGBA32)
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_BGR, size[0], size[1], 0, GL_BGR, GL_UNSIGNED_BYTE, data);
|
format = GL_RGBA;
|
||||||
} else if (pixelFormat == PixelFormat::BGRA32) {
|
else if (pixelFormat == PixelFormat::BGR24)
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA, size[0], size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
format = GL_BGR;
|
||||||
} else {
|
else if (pixelFormat == PixelFormat::BGRA32)
|
||||||
starAssert(false);
|
format = GL_BGRA;
|
||||||
}
|
else
|
||||||
|
throw RendererException("Unsupported texture format in OpenGL20Renderer::uploadTextureImage");
|
||||||
|
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, format, size[0], size[1], 0, format, GL_UNSIGNED_BYTE, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OpenGl20Renderer::flushImmediatePrimitives() {
|
void OpenGl20Renderer::flushImmediatePrimitives() {
|
||||||
@ -752,9 +821,6 @@ auto OpenGl20Renderer::createGlTexture(Image const& image, TextureAddressing add
|
|||||||
glLoneTexture->textureAddressing = addressing;
|
glLoneTexture->textureAddressing = addressing;
|
||||||
glLoneTexture->textureSize = image.size();
|
glLoneTexture->textureSize = image.size();
|
||||||
|
|
||||||
if (image.empty())
|
|
||||||
return glLoneTexture;
|
|
||||||
|
|
||||||
glGenTextures(1, &glLoneTexture->textureId);
|
glGenTextures(1, &glLoneTexture->textureId);
|
||||||
if (glLoneTexture->textureId == 0)
|
if (glLoneTexture->textureId == 0)
|
||||||
throw RendererException("Could not generate texture in OpenGL20Renderer::createGlTexture");
|
throw RendererException("Could not generate texture in OpenGL20Renderer::createGlTexture");
|
||||||
@ -777,7 +843,9 @@ auto OpenGl20Renderer::createGlTexture(Image const& image, TextureAddressing add
|
|||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
}
|
}
|
||||||
|
|
||||||
uploadTextureImage(image.pixelFormat(), image.size(), image.data());
|
|
||||||
|
if (!image.empty())
|
||||||
|
uploadTextureImage(image.pixelFormat(), image.size(), image.data());
|
||||||
|
|
||||||
return glLoneTexture;
|
return glLoneTexture;
|
||||||
}
|
}
|
||||||
@ -852,6 +920,37 @@ void OpenGl20Renderer::setupGlUniforms(Effect& effect) {
|
|||||||
glUniform2f(m_screenSizeUniform, m_screenSize[0], m_screenSize[1]);
|
glUniform2f(m_screenSizeUniform, m_screenSize[0], m_screenSize[1]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RefPtr<OpenGl20Renderer::GlFrameBuffer> OpenGl20Renderer::getGlFrameBuffer(String const& id) {
|
||||||
|
if (auto ptr = m_frameBuffers.ptr(id))
|
||||||
|
return *ptr;
|
||||||
|
else
|
||||||
|
throw RendererException::format("Frame buffer '{}' does not exist", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGl20Renderer::blitGlFrameBuffer(RefPtr<GlFrameBuffer> const& frameBuffer) {
|
||||||
|
if (frameBuffer->blitted)
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& size = m_screenSize;
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
|
||||||
|
glBindFramebuffer(GL_READ_FRAMEBUFFER, frameBuffer->id);
|
||||||
|
glBlitFramebuffer(
|
||||||
|
0, 0, size[0], size[1],
|
||||||
|
0, 0, size[0], size[1],
|
||||||
|
GL_COLOR_BUFFER_BIT, GL_NEAREST
|
||||||
|
);
|
||||||
|
|
||||||
|
frameBuffer->blitted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OpenGl20Renderer::switchGlFrameBuffer(RefPtr<GlFrameBuffer> const& frameBuffer) {
|
||||||
|
if (m_currentFrameBuffer == frameBuffer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, frameBuffer->id);
|
||||||
|
m_currentFrameBuffer = frameBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
GLuint OpenGl20Renderer::Effect::getAttribute(String const& name) {
|
GLuint OpenGl20Renderer::Effect::getAttribute(String const& name) {
|
||||||
auto find = attributes.find(name);
|
auto find = attributes.find(name);
|
||||||
if (find == attributes.end()) {
|
if (find == attributes.end()) {
|
||||||
|
@ -10,6 +10,8 @@ namespace Star {
|
|||||||
|
|
||||||
STAR_CLASS(OpenGl20Renderer);
|
STAR_CLASS(OpenGl20Renderer);
|
||||||
|
|
||||||
|
constexpr size_t FrameBufferCount = 1;
|
||||||
|
|
||||||
// OpenGL 2.0 implementation of Renderer. OpenGL context must be created and
|
// OpenGL 2.0 implementation of Renderer. OpenGL context must be created and
|
||||||
// active during construction, destruction, and all method calls.
|
// active during construction, destruction, and all method calls.
|
||||||
class OpenGl20Renderer : public Renderer {
|
class OpenGl20Renderer : public Renderer {
|
||||||
@ -20,6 +22,7 @@ public:
|
|||||||
String rendererId() const override;
|
String rendererId() const override;
|
||||||
Vec2U screenSize() const override;
|
Vec2U screenSize() const override;
|
||||||
|
|
||||||
|
void loadConfig(Json const& config) override;
|
||||||
void loadEffectConfig(String const& name, Json const& effectConfig, StringMap<String> const& shaders) override;
|
void loadEffectConfig(String const& name, Json const& effectConfig, StringMap<String> const& shaders) override;
|
||||||
|
|
||||||
void setEffectParameter(String const& parameterName, RenderEffectParameter const& parameter) override;
|
void setEffectParameter(String const& parameterName, RenderEffectParameter const& parameter) override;
|
||||||
@ -145,22 +148,33 @@ private:
|
|||||||
|
|
||||||
struct EffectParameter {
|
struct EffectParameter {
|
||||||
GLint parameterUniform = -1;
|
GLint parameterUniform = -1;
|
||||||
VariantTypeIndex parameterType;
|
VariantTypeIndex parameterType = 0;
|
||||||
Maybe<RenderEffectParameter> parameterValue;
|
Maybe<RenderEffectParameter> parameterValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct EffectTexture {
|
struct EffectTexture {
|
||||||
GLint textureUniform = -1;
|
GLint textureUniform = -1;
|
||||||
unsigned textureUnit;
|
unsigned textureUnit = 0;
|
||||||
TextureAddressing textureAddressing = TextureAddressing::Clamp;
|
TextureAddressing textureAddressing = TextureAddressing::Clamp;
|
||||||
TextureFiltering textureFiltering = TextureFiltering::Linear;
|
TextureFiltering textureFiltering = TextureFiltering::Linear;
|
||||||
GLint textureSizeUniform = -1;
|
GLint textureSizeUniform = -1;
|
||||||
RefPtr<GlLoneTexture> textureValue;
|
RefPtr<GlLoneTexture> textureValue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GlFrameBuffer : RefCounter {
|
||||||
|
GLuint id = 0;
|
||||||
|
RefPtr<GlLoneTexture> texture;
|
||||||
|
|
||||||
|
Json config;
|
||||||
|
bool blitted = false;
|
||||||
|
|
||||||
|
GlFrameBuffer(Json const& config);
|
||||||
|
~GlFrameBuffer();
|
||||||
|
};
|
||||||
|
|
||||||
class Effect {
|
class Effect {
|
||||||
public:
|
public:
|
||||||
GLuint program;
|
GLuint program = 0;
|
||||||
Json config;
|
Json config;
|
||||||
StringMap<EffectParameter> parameters;
|
StringMap<EffectParameter> parameters;
|
||||||
StringMap<EffectTexture> textures;
|
StringMap<EffectTexture> textures;
|
||||||
@ -185,6 +199,10 @@ private:
|
|||||||
|
|
||||||
void setupGlUniforms(Effect& effect);
|
void setupGlUniforms(Effect& effect);
|
||||||
|
|
||||||
|
RefPtr<OpenGl20Renderer::GlFrameBuffer> getGlFrameBuffer(String const& id);
|
||||||
|
void blitGlFrameBuffer(RefPtr<OpenGl20Renderer::GlFrameBuffer> const& frameBuffer);
|
||||||
|
void switchGlFrameBuffer(RefPtr<OpenGl20Renderer::GlFrameBuffer> const& frameBuffer);
|
||||||
|
|
||||||
Vec2U m_screenSize;
|
Vec2U m_screenSize;
|
||||||
|
|
||||||
GLuint m_program = 0;
|
GLuint m_program = 0;
|
||||||
@ -203,6 +221,9 @@ private:
|
|||||||
StringMap<Effect> m_effects;
|
StringMap<Effect> m_effects;
|
||||||
Effect* m_currentEffect;
|
Effect* m_currentEffect;
|
||||||
|
|
||||||
|
StringMap<RefPtr<GlFrameBuffer>> m_frameBuffers;
|
||||||
|
RefPtr<GlFrameBuffer> m_currentFrameBuffer;
|
||||||
|
|
||||||
RefPtr<GlTexture> m_whiteTexture;
|
RefPtr<GlTexture> m_whiteTexture;
|
||||||
|
|
||||||
Maybe<RectI> m_scissorRect;
|
Maybe<RectI> m_scissorRect;
|
||||||
|
@ -211,7 +211,7 @@ void ClientApplication::renderInit(RendererPtr renderer) {
|
|||||||
auto assets = m_root->assets();
|
auto assets = m_root->assets();
|
||||||
|
|
||||||
auto loadEffectConfig = [&](String const& name) {
|
auto loadEffectConfig = [&](String const& name) {
|
||||||
String path = strf("/rendering/{}.config", name);
|
String path = strf("/rendering/effects/{}.config", name);
|
||||||
if (assets->assetExists(path)) {
|
if (assets->assetExists(path)) {
|
||||||
StringMap<String> shaders;
|
StringMap<String> shaders;
|
||||||
auto config = assets->json(path);
|
auto config = assets->json(path);
|
||||||
@ -233,6 +233,8 @@ void ClientApplication::renderInit(RendererPtr renderer) {
|
|||||||
Logger::warn("No rendering config found for renderer with id '{}'", renderer->rendererId());
|
Logger::warn("No rendering config found for renderer with id '{}'", renderer->rendererId());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
renderer->loadConfig(assets->json("/rendering/opengl20.config"));
|
||||||
|
|
||||||
loadEffectConfig("world");
|
loadEffectConfig("world");
|
||||||
loadEffectConfig("interface");
|
loadEffectConfig("interface");
|
||||||
|
|
||||||
@ -372,6 +374,9 @@ void ClientApplication::update() {
|
|||||||
void ClientApplication::render() {
|
void ClientApplication::render() {
|
||||||
auto config = m_root->configuration();
|
auto config = m_root->configuration();
|
||||||
auto assets = m_root->assets();
|
auto assets = m_root->assets();
|
||||||
|
auto& renderer = Application::renderer();
|
||||||
|
|
||||||
|
renderer->switchEffectConfig("interface");
|
||||||
|
|
||||||
if (m_guiContext->windowWidth() >= m_crossoverRes[0] && m_guiContext->windowHeight() >= m_crossoverRes[1])
|
if (m_guiContext->windowWidth() >= m_crossoverRes[0] && m_guiContext->windowHeight() >= m_crossoverRes[1])
|
||||||
m_guiContext->setInterfaceScale(m_maxInterfaceScale);
|
m_guiContext->setInterfaceScale(m_maxInterfaceScale);
|
||||||
@ -387,28 +392,21 @@ void ClientApplication::render() {
|
|||||||
|
|
||||||
} else if (m_state > MainAppState::Title) {
|
} else if (m_state > MainAppState::Title) {
|
||||||
WorldClientPtr worldClient = m_universeClient->worldClient();
|
WorldClientPtr worldClient = m_universeClient->worldClient();
|
||||||
|
|
||||||
RendererPtr renderer = Application::renderer();
|
|
||||||
renderer->switchEffectConfig("world");
|
|
||||||
if (worldClient) {
|
if (worldClient) {
|
||||||
auto totalStart = Time::monotonicMicroseconds();
|
auto totalStart = Time::monotonicMicroseconds();
|
||||||
auto start = totalStart;
|
renderer->switchEffectConfig("world");
|
||||||
|
auto clientStart = totalStart;
|
||||||
worldClient->render(m_renderData, TilePainter::BorderTileSize);
|
worldClient->render(m_renderData, TilePainter::BorderTileSize);
|
||||||
LogMap::set("client_render_world_client", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - start));
|
LogMap::set("client_render_world_client", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - clientStart));
|
||||||
|
|
||||||
start = Time::monotonicMicroseconds();
|
auto paintStart = Time::monotonicMicroseconds();
|
||||||
m_worldPainter->render(m_renderData, [&]() { worldClient->waitForLighting(); });
|
m_worldPainter->render(m_renderData, [&]() { worldClient->waitForLighting(); });
|
||||||
LogMap::set("client_render_world_painter", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - start));
|
LogMap::set("client_render_world_painter", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - paintStart));
|
||||||
|
|
||||||
start = Time::monotonicMicroseconds();
|
|
||||||
m_mainInterface->renderInWorldElements();
|
|
||||||
LogMap::set("client_render_world_elements", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - start));
|
|
||||||
|
|
||||||
LogMap::set("client_render_world_total", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - totalStart));
|
LogMap::set("client_render_world_total", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - totalStart));
|
||||||
}
|
}
|
||||||
renderer->switchEffectConfig("interface");
|
renderer->switchEffectConfig("interface");
|
||||||
auto start = Time::monotonicMicroseconds();
|
auto start = Time::monotonicMicroseconds();
|
||||||
|
m_mainInterface->renderInWorldElements();
|
||||||
m_mainInterface->render();
|
m_mainInterface->render();
|
||||||
m_cinematicOverlay->render();
|
m_cinematicOverlay->render();
|
||||||
LogMap::set("client_render_interface", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - start));
|
LogMap::set("client_render_interface", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - start));
|
||||||
|
@ -127,7 +127,6 @@ void JsonStreamer<Json>::toJsonStream(Json const& val, JsonStream& stream, bool
|
|||||||
stream.endArray();
|
stream.endArray();
|
||||||
} else if (type == Json::Type::Object) {
|
} else if (type == Json::Type::Object) {
|
||||||
stream.beginObject();
|
stream.beginObject();
|
||||||
List<String::Char> chars;
|
|
||||||
if (sort) {
|
if (sort) {
|
||||||
auto objectPtr = val.objectPtr();
|
auto objectPtr = val.objectPtr();
|
||||||
List<JsonObject::const_iterator> iterators;
|
List<JsonObject::const_iterator> iterators;
|
||||||
@ -142,10 +141,8 @@ void JsonStreamer<Json>::toJsonStream(Json const& val, JsonStream& stream, bool
|
|||||||
if (!first)
|
if (!first)
|
||||||
stream.putComma();
|
stream.putComma();
|
||||||
first = false;
|
first = false;
|
||||||
chars.clear();
|
auto ws = i->first.wideString();
|
||||||
for (auto const& c : i->first)
|
stream.objectKey(ws.c_str(), ws.length());
|
||||||
chars.push_back(c);
|
|
||||||
stream.objectKey(chars.ptr(), chars.size());
|
|
||||||
stream.putColon();
|
stream.putColon();
|
||||||
toJsonStream(i->second, stream, sort);
|
toJsonStream(i->second, stream, sort);
|
||||||
}
|
}
|
||||||
|
@ -124,25 +124,32 @@ size_t TilePainter::TextureKeyHash::operator()(TextureKey const& key) const {
|
|||||||
}
|
}
|
||||||
|
|
||||||
TilePainter::ChunkHash TilePainter::terrainChunkHash(WorldRenderData& renderData, Vec2I chunkIndex) {
|
TilePainter::ChunkHash TilePainter::terrainChunkHash(WorldRenderData& renderData, Vec2I chunkIndex) {
|
||||||
XXHash3 hasher;
|
//XXHash3 hasher;
|
||||||
|
static ByteArray buffer;
|
||||||
|
buffer.clear();
|
||||||
RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance);
|
RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance);
|
||||||
|
|
||||||
forEachRenderTile(renderData, tileRange, [&](Vec2I const&, RenderTile const& renderTile) {
|
forEachRenderTile(renderData, tileRange, [&](Vec2I const&, RenderTile const& renderTile) {
|
||||||
renderTile.hashPushTerrain(hasher);
|
//renderTile.hashPushTerrain(hasher);
|
||||||
});
|
buffer.append((char*)&renderTile, offsetof(RenderTile, liquidId));
|
||||||
|
});
|
||||||
|
|
||||||
return hasher.digest();
|
//return hasher.digest();
|
||||||
|
return XXH3_64bits(buffer.ptr(), buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TilePainter::ChunkHash TilePainter::liquidChunkHash(WorldRenderData& renderData, Vec2I chunkIndex) {
|
TilePainter::ChunkHash TilePainter::liquidChunkHash(WorldRenderData& renderData, Vec2I chunkIndex) {
|
||||||
XXHash3 hasher;
|
///XXHash3 hasher;
|
||||||
RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance);
|
RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance);
|
||||||
|
static ByteArray buffer;
|
||||||
|
buffer.clear();
|
||||||
|
|
||||||
forEachRenderTile(renderData, tileRange, [&](Vec2I const&, RenderTile const& renderTile) {
|
forEachRenderTile(renderData, tileRange, [&](Vec2I const&, RenderTile const& renderTile) {
|
||||||
renderTile.hashPushLiquid(hasher);
|
//renderTile.hashPushLiquid(hasher);
|
||||||
});
|
buffer.append((char*)&renderTile.liquidId, sizeof(LiquidId) + sizeof(LiquidLevel));
|
||||||
|
});
|
||||||
|
|
||||||
return hasher.digest();
|
//return hasher.digest();
|
||||||
|
return XXH3_64bits(buffer.ptr(), buffer.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
TilePainter::QuadZLevel TilePainter::materialZLevel(uint32_t zLevel, MaterialId material, MaterialHue hue, MaterialColorVariant colorVariant) {
|
TilePainter::QuadZLevel TilePainter::materialZLevel(uint32_t zLevel, MaterialId material, MaterialHue hue, MaterialColorVariant colorVariant) {
|
||||||
|
@ -69,6 +69,8 @@ void WorldPainter::render(WorldRenderData& renderData, function<void()> lightWai
|
|||||||
m_environmentPainter->renderSky(Vec2F(m_camera.screenSize()), renderData.skyRenderData);
|
m_environmentPainter->renderSky(Vec2F(m_camera.screenSize()), renderData.skyRenderData);
|
||||||
m_environmentPainter->renderFrontOrbiters(orbiterAndPlanetRatio, Vec2F(m_camera.screenSize()), renderData.skyRenderData);
|
m_environmentPainter->renderFrontOrbiters(orbiterAndPlanetRatio, Vec2F(m_camera.screenSize()), renderData.skyRenderData);
|
||||||
|
|
||||||
|
m_renderer->flush();
|
||||||
|
|
||||||
if (lightWaiter) {
|
if (lightWaiter) {
|
||||||
auto start = Time::monotonicMicroseconds();
|
auto start = Time::monotonicMicroseconds();
|
||||||
lightWaiter();
|
lightWaiter();
|
||||||
|
Loading…
Reference in New Issue
Block a user