diff --git a/assets/opensb/rendering/default.config b/assets/opensb/rendering/default.config deleted file mode 100644 index 5e51afc..0000000 --- a/assets/opensb/rendering/default.config +++ /dev/null @@ -1,9 +0,0 @@ -{ - "effectParameters" : {}, - "effectTextures" : {}, - - "effectShaders" : { - "vertex" : "default.vert", - "fragment" : "default.frag" - } -} \ No newline at end of file diff --git a/assets/opensb/rendering/effects/interface.config b/assets/opensb/rendering/effects/interface.config new file mode 100644 index 0000000..b4860d6 --- /dev/null +++ b/assets/opensb/rendering/effects/interface.config @@ -0,0 +1,11 @@ +{ + "blitFrameBuffer" : "world", + + "effectParameters" : {}, + "effectTextures" : {}, + + "effectShaders" : { + "vertex" : "interface.vert", + "fragment" : "interface.frag" + } +} \ No newline at end of file diff --git a/assets/opensb/rendering/default.frag b/assets/opensb/rendering/effects/interface.frag similarity index 100% rename from assets/opensb/rendering/default.frag rename to assets/opensb/rendering/effects/interface.frag diff --git a/assets/opensb/rendering/default.vert b/assets/opensb/rendering/effects/interface.vert similarity index 100% rename from assets/opensb/rendering/default.vert rename to assets/opensb/rendering/effects/interface.vert diff --git a/assets/opensb/rendering/world.config b/assets/opensb/rendering/effects/world.config similarity index 97% rename from assets/opensb/rendering/world.config rename to assets/opensb/rendering/effects/world.config index 3ad0d88..188b727 100644 --- a/assets/opensb/rendering/world.config +++ b/assets/opensb/rendering/effects/world.config @@ -1,4 +1,6 @@ { + "frameBuffer" : "world", + "effectParameters" : { "lightMapEnabled" : { "type" : "bool", diff --git a/assets/opensb/rendering/world.frag b/assets/opensb/rendering/effects/world.frag similarity index 100% rename from assets/opensb/rendering/world.frag rename to assets/opensb/rendering/effects/world.frag diff --git a/assets/opensb/rendering/world.vert b/assets/opensb/rendering/effects/world.vert similarity index 100% rename from assets/opensb/rendering/world.vert rename to assets/opensb/rendering/effects/world.vert diff --git a/assets/opensb/rendering/opengl20.config.patch b/assets/opensb/rendering/opengl20.config.patch new file mode 100644 index 0000000..3d85c1a --- /dev/null +++ b/assets/opensb/rendering/opengl20.config.patch @@ -0,0 +1,5 @@ +{ + "frameBuffers" : { + "world" : {} + } +} \ No newline at end of file diff --git a/source/application/StarRenderer.hpp b/source/application/StarRenderer.hpp index 58c1c27..ad44c5c 100644 --- a/source/application/StarRenderer.hpp +++ b/source/application/StarRenderer.hpp @@ -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 diff --git a/source/application/StarRenderer_opengl20.cpp b/source/application/StarRenderer_opengl20.cpp index b54361e..f85f0e8 100644 --- a/source/application/StarRenderer_opengl20.cpp +++ b/source/application/StarRenderer_opengl20.cpp @@ -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(pair.second); +} + void OpenGl20Renderer::loadEffectConfig(String const& name, Json const& effectConfig, StringMap 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& 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& primitives) { ++currentVertexCount; }; + float textureIndex = 0.0f; + Vec2F textureOffset = {}; + Texture* lastTexture = nullptr; for (auto& primitive : primitives) { - float textureIndex; - Vec2F textureOffset; if (auto tri = primitive.ptr()) { tie(textureIndex, textureOffset) = addCurrentTexture(move(tri->texture)); @@ -678,6 +743,7 @@ void OpenGl20Renderer::GlRenderBuffer::set(List& primitives) { } else if (auto poly = primitive.ptr()) { 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::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 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 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()) { diff --git a/source/application/StarRenderer_opengl20.hpp b/source/application/StarRenderer_opengl20.hpp index 598f803..4d917d5 100644 --- a/source/application/StarRenderer_opengl20.hpp +++ b/source/application/StarRenderer_opengl20.hpp @@ -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 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 parameterValue; }; struct EffectTexture { GLint textureUniform = -1; - unsigned textureUnit; + unsigned textureUnit = 0; TextureAddressing textureAddressing = TextureAddressing::Clamp; TextureFiltering textureFiltering = TextureFiltering::Linear; GLint textureSizeUniform = -1; RefPtr textureValue; }; + + struct GlFrameBuffer : RefCounter { + GLuint id = 0; + RefPtr texture; + + Json config; + bool blitted = false; + + GlFrameBuffer(Json const& config); + ~GlFrameBuffer(); + }; class Effect { public: - GLuint program; + GLuint program = 0; Json config; StringMap parameters; StringMap textures; @@ -185,6 +199,10 @@ private: void setupGlUniforms(Effect& effect); + RefPtr getGlFrameBuffer(String const& id); + void blitGlFrameBuffer(RefPtr const& frameBuffer); + void switchGlFrameBuffer(RefPtr const& frameBuffer); + Vec2U m_screenSize; GLuint m_program = 0; @@ -203,6 +221,9 @@ private: StringMap m_effects; Effect* m_currentEffect; + StringMap> m_frameBuffers; + RefPtr m_currentFrameBuffer; + RefPtr m_whiteTexture; Maybe m_scissorRect; diff --git a/source/client/StarClientApplication.cpp b/source/client/StarClientApplication.cpp index 2ed90ab..356421b 100644 --- a/source/client/StarClientApplication.cpp +++ b/source/client/StarClientApplication.cpp @@ -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 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)); diff --git a/source/core/StarJsonBuilder.cpp b/source/core/StarJsonBuilder.cpp index 6084c40..6355666 100644 --- a/source/core/StarJsonBuilder.cpp +++ b/source/core/StarJsonBuilder.cpp @@ -127,7 +127,6 @@ void JsonStreamer::toJsonStream(Json const& val, JsonStream& stream, bool stream.endArray(); } else if (type == Json::Type::Object) { stream.beginObject(); - List chars; if (sort) { auto objectPtr = val.objectPtr(); List iterators; @@ -142,10 +141,8 @@ void JsonStreamer::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); } diff --git a/source/rendering/StarTilePainter.cpp b/source/rendering/StarTilePainter.cpp index d0a7e5a..40b3de6 100644 --- a/source/rendering/StarTilePainter.cpp +++ b/source/rendering/StarTilePainter.cpp @@ -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) { diff --git a/source/rendering/StarWorldPainter.cpp b/source/rendering/StarWorldPainter.cpp index 7bcbb45..e033ee1 100644 --- a/source/rendering/StarWorldPainter.cpp +++ b/source/rendering/StarWorldPainter.cpp @@ -69,6 +69,8 @@ void WorldPainter::render(WorldRenderData& renderData, function 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();