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" : {
|
||||
"lightMapEnabled" : {
|
||||
"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 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
|
||||
// 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
|
||||
|
@ -105,6 +105,7 @@ OpenGl20Renderer::~OpenGl20Renderer() {
|
||||
for (auto& effect : m_effects)
|
||||
glDeleteProgram(effect.second.program);
|
||||
|
||||
m_frameBuffers.clear();
|
||||
logGlErrorSummary("OpenGL errors during shutdown");
|
||||
}
|
||||
|
||||
@ -116,6 +117,38 @@ Vec2U OpenGl20Renderer::screenSize() const {
|
||||
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) {
|
||||
if (m_effects.contains(name)) {
|
||||
Logger::warn("OpenGL effect {} already exists", name);
|
||||
@ -303,6 +336,18 @@ bool OpenGl20Renderer::switchEffectConfig(String const& name) {
|
||||
return false;
|
||||
|
||||
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);
|
||||
setupGlUniforms(effect);
|
||||
@ -387,11 +432,24 @@ void OpenGl20Renderer::setScreenSize(Vec2U screenSize) {
|
||||
m_screenSize = screenSize;
|
||||
glViewport(0, 0, 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() {
|
||||
if (m_scissorRect)
|
||||
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);
|
||||
|
||||
@ -417,6 +475,9 @@ void OpenGl20Renderer::finishFrame() {
|
||||
return false;
|
||||
});
|
||||
|
||||
// Blit if another shader hasn't
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, 0);
|
||||
|
||||
if (DebugEnabled)
|
||||
logGlErrorSummary("OpenGL errors this frame");
|
||||
}
|
||||
@ -456,17 +517,20 @@ void OpenGl20Renderer::GlTextureAtlasSet::copyAtlasPixels(
|
||||
glBindTexture(GL_TEXTURE_2D, glTexture);
|
||||
|
||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||
if (image.pixelFormat() == PixelFormat::RGB24) {
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, bottomLeft[0], bottomLeft[1], image.width(), image.height(), GL_RGB, GL_UNSIGNED_BYTE, image.data());
|
||||
} else if (image.pixelFormat() == PixelFormat::RGBA32) {
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, bottomLeft[0], bottomLeft[1], image.width(), image.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.data());
|
||||
} else if (image.pixelFormat() == PixelFormat::BGR24) {
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, bottomLeft[0], bottomLeft[1], image.width(), image.height(), GL_BGR, GL_UNSIGNED_BYTE, image.data());
|
||||
} else if (image.pixelFormat() == PixelFormat::BGRA32) {
|
||||
glTexSubImage2D(GL_TEXTURE_2D, 0, bottomLeft[0], bottomLeft[1], image.width(), image.height(), GL_BGRA, GL_UNSIGNED_BYTE, image.data());
|
||||
} else {
|
||||
GLenum format;
|
||||
auto pixelFormat = image.pixelFormat();
|
||||
if (pixelFormat == PixelFormat::RGB24)
|
||||
format = GL_RGB;
|
||||
else if (pixelFormat == PixelFormat::RGBA32)
|
||||
format = GL_RGBA;
|
||||
else if (pixelFormat == PixelFormat::BGR24)
|
||||
format = GL_BGR;
|
||||
else if (pixelFormat == PixelFormat::BGRA32)
|
||||
format = GL_BGRA;
|
||||
else
|
||||
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)
|
||||
@ -608,7 +672,7 @@ void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive>& primitives) {
|
||||
glBufferData(GL_ARRAY_BUFFER, accumulationBuffer.size(), accumulationBuffer.ptr(), GL_STREAM_DRAW);
|
||||
}
|
||||
|
||||
vertexBuffers.append(vb);
|
||||
vertexBuffers.emplace_back(move(vb));
|
||||
|
||||
currentTextures.clear();
|
||||
currentTextureSizes.clear();
|
||||
@ -654,9 +718,10 @@ void OpenGl20Renderer::GlRenderBuffer::set(List<RenderPrimitive>& primitives) {
|
||||
++currentVertexCount;
|
||||
};
|
||||
|
||||
float textureIndex = 0.0f;
|
||||
Vec2F textureOffset = {};
|
||||
Texture* lastTexture = nullptr;
|
||||
for (auto& primitive : primitives) {
|
||||
float textureIndex;
|
||||
Vec2F textureOffset;
|
||||
if (auto tri = primitive.ptr<RenderTriangle>()) {
|
||||
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>()) {
|
||||
if (poly->vertexes.size() > 2) {
|
||||
tie(textureIndex, textureOffset) = addCurrentTexture(move(poly->texture));
|
||||
|
||||
for (size_t i = 1; i < poly->vertexes.size() - 1; ++i) {
|
||||
appendBufferVertex(poly->vertexes[0], 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) {
|
||||
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);
|
||||
} else if (pixelFormat == PixelFormat::RGBA32) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, size[0], size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
} else if (pixelFormat == PixelFormat::BGR24) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_BGR, size[0], size[1], 0, GL_BGR, GL_UNSIGNED_BYTE, data);
|
||||
} else if (pixelFormat == PixelFormat::BGRA32) {
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA, size[0], size[1], 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
|
||||
} else {
|
||||
starAssert(false);
|
||||
}
|
||||
|
||||
GLenum format;
|
||||
if (pixelFormat == PixelFormat::RGB24)
|
||||
format = GL_RGB;
|
||||
else if (pixelFormat == PixelFormat::RGBA32)
|
||||
format = GL_RGBA;
|
||||
else if (pixelFormat == PixelFormat::BGR24)
|
||||
format = GL_BGR;
|
||||
else if (pixelFormat == PixelFormat::BGRA32)
|
||||
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() {
|
||||
@ -752,9 +821,6 @@ auto OpenGl20Renderer::createGlTexture(Image const& image, TextureAddressing add
|
||||
glLoneTexture->textureAddressing = addressing;
|
||||
glLoneTexture->textureSize = image.size();
|
||||
|
||||
if (image.empty())
|
||||
return glLoneTexture;
|
||||
|
||||
glGenTextures(1, &glLoneTexture->textureId);
|
||||
if (glLoneTexture->textureId == 0)
|
||||
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);
|
||||
}
|
||||
|
||||
uploadTextureImage(image.pixelFormat(), image.size(), image.data());
|
||||
|
||||
if (!image.empty())
|
||||
uploadTextureImage(image.pixelFormat(), image.size(), image.data());
|
||||
|
||||
return glLoneTexture;
|
||||
}
|
||||
@ -852,6 +920,37 @@ void OpenGl20Renderer::setupGlUniforms(Effect& effect) {
|
||||
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) {
|
||||
auto find = attributes.find(name);
|
||||
if (find == attributes.end()) {
|
||||
|
@ -10,6 +10,8 @@ namespace Star {
|
||||
|
||||
STAR_CLASS(OpenGl20Renderer);
|
||||
|
||||
constexpr size_t FrameBufferCount = 1;
|
||||
|
||||
// OpenGL 2.0 implementation of Renderer. OpenGL context must be created and
|
||||
// active during construction, destruction, and all method calls.
|
||||
class OpenGl20Renderer : public Renderer {
|
||||
@ -20,6 +22,7 @@ public:
|
||||
String rendererId() 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 setEffectParameter(String const& parameterName, RenderEffectParameter const& parameter) override;
|
||||
@ -145,22 +148,33 @@ private:
|
||||
|
||||
struct EffectParameter {
|
||||
GLint parameterUniform = -1;
|
||||
VariantTypeIndex parameterType;
|
||||
VariantTypeIndex parameterType = 0;
|
||||
Maybe<RenderEffectParameter> parameterValue;
|
||||
};
|
||||
|
||||
struct EffectTexture {
|
||||
GLint textureUniform = -1;
|
||||
unsigned textureUnit;
|
||||
unsigned textureUnit = 0;
|
||||
TextureAddressing textureAddressing = TextureAddressing::Clamp;
|
||||
TextureFiltering textureFiltering = TextureFiltering::Linear;
|
||||
GLint textureSizeUniform = -1;
|
||||
RefPtr<GlLoneTexture> textureValue;
|
||||
};
|
||||
|
||||
struct GlFrameBuffer : RefCounter {
|
||||
GLuint id = 0;
|
||||
RefPtr<GlLoneTexture> texture;
|
||||
|
||||
Json config;
|
||||
bool blitted = false;
|
||||
|
||||
GlFrameBuffer(Json const& config);
|
||||
~GlFrameBuffer();
|
||||
};
|
||||
|
||||
class Effect {
|
||||
public:
|
||||
GLuint program;
|
||||
GLuint program = 0;
|
||||
Json config;
|
||||
StringMap<EffectParameter> parameters;
|
||||
StringMap<EffectTexture> textures;
|
||||
@ -185,6 +199,10 @@ private:
|
||||
|
||||
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;
|
||||
|
||||
GLuint m_program = 0;
|
||||
@ -203,6 +221,9 @@ private:
|
||||
StringMap<Effect> m_effects;
|
||||
Effect* m_currentEffect;
|
||||
|
||||
StringMap<RefPtr<GlFrameBuffer>> m_frameBuffers;
|
||||
RefPtr<GlFrameBuffer> m_currentFrameBuffer;
|
||||
|
||||
RefPtr<GlTexture> m_whiteTexture;
|
||||
|
||||
Maybe<RectI> m_scissorRect;
|
||||
|
@ -211,7 +211,7 @@ void ClientApplication::renderInit(RendererPtr renderer) {
|
||||
auto assets = m_root->assets();
|
||||
|
||||
auto loadEffectConfig = [&](String const& name) {
|
||||
String path = strf("/rendering/{}.config", name);
|
||||
String path = strf("/rendering/effects/{}.config", name);
|
||||
if (assets->assetExists(path)) {
|
||||
StringMap<String> shaders;
|
||||
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());
|
||||
};
|
||||
|
||||
renderer->loadConfig(assets->json("/rendering/opengl20.config"));
|
||||
|
||||
loadEffectConfig("world");
|
||||
loadEffectConfig("interface");
|
||||
|
||||
@ -372,6 +374,9 @@ void ClientApplication::update() {
|
||||
void ClientApplication::render() {
|
||||
auto config = m_root->configuration();
|
||||
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])
|
||||
m_guiContext->setInterfaceScale(m_maxInterfaceScale);
|
||||
@ -387,28 +392,21 @@ void ClientApplication::render() {
|
||||
|
||||
} else if (m_state > MainAppState::Title) {
|
||||
WorldClientPtr worldClient = m_universeClient->worldClient();
|
||||
|
||||
RendererPtr renderer = Application::renderer();
|
||||
renderer->switchEffectConfig("world");
|
||||
if (worldClient) {
|
||||
auto totalStart = Time::monotonicMicroseconds();
|
||||
auto start = totalStart;
|
||||
|
||||
renderer->switchEffectConfig("world");
|
||||
auto clientStart = totalStart;
|
||||
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(); });
|
||||
LogMap::set("client_render_world_painter", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - start));
|
||||
|
||||
start = Time::monotonicMicroseconds();
|
||||
m_mainInterface->renderInWorldElements();
|
||||
LogMap::set("client_render_world_elements", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - start));
|
||||
|
||||
LogMap::set("client_render_world_painter", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - paintStart));
|
||||
LogMap::set("client_render_world_total", strf(u8"{:05d}\u00b5s", Time::monotonicMicroseconds() - totalStart));
|
||||
}
|
||||
renderer->switchEffectConfig("interface");
|
||||
auto start = Time::monotonicMicroseconds();
|
||||
m_mainInterface->renderInWorldElements();
|
||||
m_mainInterface->render();
|
||||
m_cinematicOverlay->render();
|
||||
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();
|
||||
} else if (type == Json::Type::Object) {
|
||||
stream.beginObject();
|
||||
List<String::Char> chars;
|
||||
if (sort) {
|
||||
auto objectPtr = val.objectPtr();
|
||||
List<JsonObject::const_iterator> iterators;
|
||||
@ -142,10 +141,8 @@ void JsonStreamer<Json>::toJsonStream(Json const& val, JsonStream& stream, bool
|
||||
if (!first)
|
||||
stream.putComma();
|
||||
first = false;
|
||||
chars.clear();
|
||||
for (auto const& c : i->first)
|
||||
chars.push_back(c);
|
||||
stream.objectKey(chars.ptr(), chars.size());
|
||||
auto ws = i->first.wideString();
|
||||
stream.objectKey(ws.c_str(), ws.length());
|
||||
stream.putColon();
|
||||
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) {
|
||||
XXHash3 hasher;
|
||||
//XXHash3 hasher;
|
||||
static ByteArray buffer;
|
||||
buffer.clear();
|
||||
RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance);
|
||||
|
||||
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) {
|
||||
XXHash3 hasher;
|
||||
///XXHash3 hasher;
|
||||
RectI tileRange = RectI::withSize(chunkIndex * RenderChunkSize, Vec2I::filled(RenderChunkSize)).padded(MaterialRenderProfileMaxNeighborDistance);
|
||||
static ByteArray buffer;
|
||||
buffer.clear();
|
||||
|
||||
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) {
|
||||
|
@ -69,6 +69,8 @@ void WorldPainter::render(WorldRenderData& renderData, function<void()> lightWai
|
||||
m_environmentPainter->renderSky(Vec2F(m_camera.screenSize()), renderData.skyRenderData);
|
||||
m_environmentPainter->renderFrontOrbiters(orbiterAndPlanetRatio, Vec2F(m_camera.screenSize()), renderData.skyRenderData);
|
||||
|
||||
m_renderer->flush();
|
||||
|
||||
if (lightWaiter) {
|
||||
auto start = Time::monotonicMicroseconds();
|
||||
lightWaiter();
|
||||
|
Loading…
Reference in New Issue
Block a user