From 3f62034c40f4d026daf89ef5adb37aab923c47d6 Mon Sep 17 00:00:00 2001 From: T1ti <40864460+T1ti@users.noreply.github.com> Date: Fri, 30 Aug 2024 21:29:33 +0200 Subject: [PATCH] Light editor updates WIP --- src/noggit/MapView.cpp | 3 +- src/noggit/Sky.cpp | 357 ++++++---- src/noggit/Sky.h | 76 ++- src/noggit/rendering/WorldRender.cpp | 34 +- .../ui/tools/LightEditor/LightEditor.cpp | 645 ++++++++++++------ .../ui/tools/LightEditor/LightEditor.hpp | 36 +- src/noggit/ui/widgets/LightViewWidget.cpp | 35 +- 7 files changed, 844 insertions(+), 342 deletions(-) diff --git a/src/noggit/MapView.cpp b/src/noggit/MapView.cpp index 2a47fa46..db29f876 100755 --- a/src/noggit/MapView.cpp +++ b/src/noggit/MapView.cpp @@ -4505,7 +4505,8 @@ void MapView::tick (float dt) _world->time += this->mTimespeed * dt; _world->animtime += dt * 1000.0f; - lightEditor->UpdateWorldTime(); + if (mTimespeed > 0.0f) + lightEditor->UpdateWorldTime(); if (_draw_model_animations.get()) { diff --git a/src/noggit/Sky.cpp b/src/noggit/Sky.cpp index 4552c637..b505e1dd 100755 --- a/src/noggit/Sky.cpp +++ b/src/noggit/Sky.cpp @@ -37,15 +37,15 @@ SkyParam::SkyParam(int paramId, Noggit::NoggitRenderContext context) if (paramId == 0) return; // don't initialise entry - for (int i = 0; i < 36; ++i) - { - mmin[i] = -2; - } - - for (int i = 0; i < 6; ++i) - { - mmin_float[i] = -2; - } + // for (int i = 0; i < NUM_SkyColorNames; ++i) + // { + // mmin[i] = -2; + // } + // + // for (int i = 0; i < NUM_SkyFloatParamsNames; ++i) + // { + // mmin_float[i] = -2; + // } // int light_param_0 = data->getInt(LightDB::DataIDs); int light_int_start = paramId * NUM_SkyColorNames - 17; @@ -59,11 +59,12 @@ SkyParam::SkyParam(int paramId, Noggit::NoggitRenderContext context) if (entries == 0) { - mmin[i] = -1; + // mmin[i] = -1; } else { - mmin[i] = rec.getInt(LightIntBandDB::Times); + // smallest/first time value + // mmin[i] = rec.getInt(LightIntBandDB::Times); for (int l = 0; l < entries; l++) { SkyColor sc(rec.getInt(LightIntBandDB::Times + l), rec.getInt(LightIntBandDB::Values + l)); @@ -106,11 +107,11 @@ SkyParam::SkyParam(int paramId, Noggit::NoggitRenderContext context) if (entries == 0) { - mmin_float[i] = -1; + // mmin_float[i] = -1; } else { - mmin_float[i] = rec.getInt(LightFloatBandDB::Times); + // mmin_float[i] = rec.getInt(LightFloatBandDB::Times); for (int l = 0; l < entries; l++) { SkyFloatParam sc(rec.getInt(LightFloatBandDB::Times + l), rec.getFloat(LightFloatBandDB::Values + l)); @@ -156,7 +157,9 @@ SkyParam::SkyParam(int paramId, Noggit::NoggitRenderContext context) if (skybox_id) { - skybox.emplace(gLightSkyboxDB.getByID(skybox_id).getString(LightSkyboxDB::filename), _context); + auto skyboxRec = gLightSkyboxDB.getByID(skybox_id); + skybox.emplace(skyboxRec.getString(LightSkyboxDB::filename), _context); + skyboxFlags = skyboxRec.getInt(LightSkyboxDB::flags); } } catch (...) @@ -171,6 +174,7 @@ Sky::Sky(DBCFile::Iterator data, Noggit::NoggitRenderContext context) , _selected(false) { Id = data->getInt(LightDB::ID); + mapId = data->getInt(LightDB::Map); pos = glm::vec3(data->getFloat(LightDB::PositionX) / skymul, data->getFloat(LightDB::PositionY) / skymul, data->getFloat(LightDB::PositionZ) / skymul); r1 = data->getFloat(LightDB::RadiusInner) / skymul; r2 = data->getFloat(LightDB::RadiusOuter) / skymul; @@ -194,7 +198,8 @@ Sky::Sky(DBCFile::Iterator data, Noggit::NoggitRenderContext context) float Sky::floatParamFor(int r, int t) const { auto sky_param = skyParams[curr_sky_param]; - if (sky_param->mmin_float[r]<0) + // if (sky_param->mmin_float[r]<0) + if (sky_param->floatParams[r].empty()) { return 0.0; } @@ -202,7 +207,7 @@ float Sky::floatParamFor(int r, int t) const int t1, t2; size_t last = sky_param->floatParams[r].size() - 1; - if (t< sky_param->mmin_float[r]) + if (t < sky_param->floatParams[r].front().time) { // reverse interpolate c1 = sky_param->floatParams[r][last].value; @@ -242,7 +247,8 @@ float Sky::floatParamFor(int r, int t) const glm::vec3 Sky::colorFor(int r, int t) const { auto sky_param = skyParams[curr_sky_param]; - if (sky_param->mmin[r]<0) + // if (sky_param->mmin[r]<0) + if (sky_param->colorRows[r].empty()) { return glm::vec3(0, 0, 0); } @@ -260,7 +266,9 @@ glm::vec3 Sky::colorFor(int r, int t) const } else { - if (t < sky_param->mmin[r]) + + // if (t < sky_param->mmin[r]) + if (t < sky_param->colorRows[r].front().time) { // reverse interpolate c1 = sky_param->colorRows[r][last].color; @@ -354,6 +362,36 @@ Skies::Skies(unsigned int mapid, Noggit::NoggitRenderContext context) std::sort(skies.begin(), skies.end()); } +Sky* Skies::createNewSky(Sky* old_sky, unsigned int new_id, glm::vec3& pos) +{ + Sky new_sky_copy = *old_sky; + new_sky_copy.Id = new_id; + new_sky_copy.pos = pos; + + new_sky_copy.weight = 0.f; + new_sky_copy.is_new_record = true; + + new_sky_copy.save_to_dbc(); + + skies.push_back(new_sky_copy); + + numSkies++; + + // refresh rendering & weights + std::sort(skies.begin(), skies.end()); + force_update(); + + for (Sky& sky : skies) + { + if (sky.Id == new_id) + { + return &sky; + } + } + return nullptr; +} + +// returns the global light, not the highest weight Sky* Skies::findSkyWeights(glm::vec3 pos) { Sky* default_sky = nullptr; @@ -404,7 +442,10 @@ Sky* Skies::findClosestSkyByWeight() Sky* closest_sky = &skies[0]; for (auto& sky : skies) { - if (sky.weight > closest_sky->weight) + // use >= to make sure when we have multiple with the same weight, + // last one has priority, because it is the closest + // skies is sorted by distance to center + if (sky.weight > 0.0f && sky.weight >= closest_sky->weight) closest_sky = &sky; } return closest_sky; @@ -442,10 +483,11 @@ void Skies::setCurrentParam(int param_id) void Skies::update_sky_colors(glm::vec3 pos, int time) { - if (numSkies == 0 || (_last_time == time && _last_pos == pos)) + if (numSkies == 0 || (_last_time == time && _last_pos == pos && !_force_update)) { return; - } + } + _force_update = false; Sky* default_sky = findSkyWeights(pos); @@ -476,14 +518,14 @@ void Skies::update_sky_colors(glm::vec3 pos, int time) color_set[i] = glm::vec3(1, 1, 1); } - _fog_multiplier = 0.f; - _fog_distance = 0.f; + _fog_multiplier = 0.1; + _fog_distance = 6500; - _river_shallow_alpha = 0.f; - _river_deep_alpha = 0.f; - _ocean_shallow_alpha = 0.f; - _ocean_deep_alpha = 0.f; - _glow = 0.0f; + _river_shallow_alpha = 0.5f; + _river_deep_alpha = 1.0f; + _ocean_shallow_alpha = 0.75f; + _ocean_deep_alpha = 1.0f; + _glow = 0.5f; } @@ -492,10 +534,10 @@ void Skies::update_sky_colors(glm::vec3 pos, int time) { Sky const& sky = skies[j]; - if (sky.weight>0) + if (sky.weight > 0.f) { // now calculate the color rows - for (int i = 0; i1.0f) || (sky.colorFor(i, time).y>1.0f) || (sky.colorFor(i, time).z>1.0f)) { @@ -583,16 +625,22 @@ bool Skies::draw(glm::mat4x4 const& model_view } } - bool has_skybox = false; if (draw_skybox) { + bool combine_flag = false; + bool has_skybox = false; + + // only draw one skybox model ? for (Sky& sky : skies) { - if (sky.weight > 0.f && sky.skybox) + if (sky.weight > 0.f && sky.skyParams[sky.curr_sky_param]->skybox) { has_skybox = true; + + if ((sky.skyParams[sky.curr_sky_param]->skyboxFlags & LIGHT_SKYBOX_COMBINE)) + combine_flag = true; // flag 0x2 = still render stars, sun and moons and clouds - auto& model = sky.skybox.value(); + auto& model = sky.skyParams[sky.curr_sky_param]->skybox.value(); model.model->trans = sky.weight; model.pos = camera_pos; model.scale = 0.1f; @@ -611,12 +659,18 @@ bool Skies::draw(glm::mat4x4 const& model_view m2_shader.uniform("tex_unit_lookup_1", 0); m2_shader.uniform("tex_unit_lookup_2", 0); m2_shader.uniform("pixel_shader", 0); + + // TODO : implement flag LIGHT_SKYBOX_FULL_DAY + if ((sky.skyParams[sky.curr_sky_param]->skyboxFlags & LIGHT_SKYBOX_FULL_DAY)) + { + // animtime = ... + } model.model->renderer()->draw(model_view, model, m2_shader, model_render_state, frustum, 1000000, camera_pos, animtime, display_mode::in_3D); } } // if it's night, draw the stars - if (light_stats.nightIntensity > 0 /* && !has_skybox*/) + if (light_stats.nightIntensity > 0 && (combine_flag || !has_skybox)) { stars.model->trans = light_stats.nightIntensity; stars.pos = camera_pos; @@ -932,136 +986,197 @@ void Sky::save_to_dbc() // find new empty ID : gLightDB.getEmptyRecordID(); .prob do it when creating new light instead. try { - DBCFile::Record data = is_new_record ? gLightDB.addRecord(Id) : gLightDB.getByID(Id); + // assuming a new unused id is already set with is_new_record + DBCFile::Record lightDbRecord = is_new_record ? gLightDB.addRecord(Id) : gLightDB.getByID(Id); - // pos = glm::vec3(data->getFloat(LightDB::PositionX) / skymul, data->getFloat(LightDB::PositionY) / skymul, data->getFloat(LightDB::PositionZ) / skymul); - // record.write(1, _curr_sky-> map id - data.write(LightDB::PositionX, pos.x * skymul); - data.write(LightDB::PositionY, pos.y * skymul); - data.write(LightDB::PositionZ, pos.z * skymul); - data.write(LightDB::RadiusInner, r1 * skymul); - data.write(LightDB::RadiusOuter,r2 * skymul); + if (is_new_record) + lightDbRecord.write(LightDB::Map, mapId); + + lightDbRecord.write(LightDB::PositionX, pos.x * skymul); + lightDbRecord.write(LightDB::PositionY, pos.y * skymul); + lightDbRecord.write(LightDB::PositionZ, pos.z * skymul); + lightDbRecord.write(LightDB::RadiusInner, r1 * skymul); + lightDbRecord.write(LightDB::RadiusOuter,r2 * skymul); // data.write(7, Params Id TODO only needed for new entries - // save LightParams.dbc - // TODO : all params, not just clear. + bool save_param_dbc = false; + bool save_colors_dbc = false; + bool save_floats_dbc = false; + bool save_skybox_dbc = false; + for (int param_id = 0; param_id < NUM_SkyFloatParamsNames; param_id++) - { + { + SkyParam* sky_param = skyParams[param_id]; // skip if no param - if (skyParams[param_id] == nullptr) + if (sky_param == nullptr) continue; + assert(sky_param->Id > 0); + + lightDbRecord.write(LightDB::DataIDs + param_id, sky_param->Id); + + // if (!sky_param->_need_save && !sky_param->_is_new_param_record) + // continue; + // TODO : several lights can use the same param, ask user if he wants to save a copy or edit it for all ? - int lightParam_dbc_id = 0; - if (is_new_record) // not for duplicates - lightParam_dbc_id = gLightParamsDB.getEmptyRecordID(); - else - lightParam_dbc_id = data.getInt(LightDB::DataIDs + param_id); + int lightParam_dbc_id = sky_param->_is_new_param_record ? gLightParamsDB.getEmptyRecordID() + : lightDbRecord.getInt(LightDB::DataIDs + param_id); if (lightParam_dbc_id == 0) continue; - int light_int_start = lightParam_dbc_id * NUM_SkyColorNames - 17; - - for (int i = 0; i < NUM_SkyColorNames; ++i) + // save lightparams.dbc + if (sky_param->_need_save || sky_param->_is_new_param_record) { + save_param_dbc = true; try { - DBCFile::Record rec = is_new_record ? gLightIntBandDB.addRecord(light_int_start + i) : gLightIntBandDB.getByID(light_int_start + i); - // int entries = rec.getInt(LightIntBandDB::Entries); - int entries = static_cast(skyParams[param_id]->colorRows[i].size()); + DBCFile::Record light_param = sky_param->_is_new_param_record ? gLightParamsDB.addRecord(lightParam_dbc_id) + : gLightParamsDB.getByID(lightParam_dbc_id); - rec.write(LightIntBandDB::Entries, entries); // nb of entries + light_param.write(LightParamsDB::highlightSky, int(sky_param->highlight_sky())); + light_param.write(LightParamsDB::water_shallow_alpha, sky_param->river_shallow_alpha()); + light_param.write(LightParamsDB::water_deep_alpha, sky_param->river_deep_alpha()); + light_param.write(LightParamsDB::ocean_shallow_alpha, sky_param->ocean_shallow_alpha()); + light_param.write(LightParamsDB::ocean_deep_alpha, sky_param->ocean_deep_alpha()); + light_param.write(LightParamsDB::glow, sky_param->glow()); - for (int l = 0; l < 16; l++) + if (sky_param->skybox.has_value()) // TODO skybox dbc { - if (l >= entries) + // try to find an existing record with those params + bool exists = false; + for (DBCFile::Iterator i = gLightSkyboxDB.begin(); i != gLightSkyboxDB.end(); ++i) { - rec.write(LightIntBandDB::Times + l, 0); - rec.write(LightIntBandDB::Values + l, 0); + if (i->getString(LightSkyboxDB::filename) == sky_param->skybox.value().model->file_key().filepath() + && i->getInt(LightSkyboxDB::flags) == sky_param->skyboxFlags) + { + int id = i->getInt(LightSkyboxDB::ID); + light_param.write(LightParamsDB::skybox, id); + exists = true; + break; + } } - else + + if (!exists) // doesn't exist, create a new record { - rec.write(LightIntBandDB::Times + l, skyParams[param_id]->colorRows[i][l].time); - - int rebuilt_color_int = static_cast(skyParams[param_id]->colorRows[i][l].color.z * 255.0f) - + (static_cast(skyParams[param_id]->colorRows[i][l].color.y * 255.0f) << 8) - + (static_cast(skyParams[param_id]->colorRows[i][l].color.x * 255.0f) << 16); - rec.write(LightIntBandDB::Values + l, rebuilt_color_int); + int new_skybox_dbc_id = gLightSkyboxDB.getEmptyRecordID(); + DBCFile::Record rec = gLightSkyboxDB.addRecord(new_skybox_dbc_id); + rec.writeString(LightSkyboxDB::filename, sky_param->skybox.value().model->file_key().filepath()); + rec.write(LightSkyboxDB::flags, sky_param->skyboxFlags); + + gLightSkyboxDB.save(); + + light_param.write(LightParamsDB::skybox, new_skybox_dbc_id); } } + else + light_param.write(LightParamsDB::skybox, 0); } - catch (...) + catch (DBCFile::NotFound) { assert(false); - LogError << "When trying to save sky colors, sky id : " << data.getInt(LightDB::ID) << std::endl; + LogError << "When trying to get the lightparams for the entry " << lightParam_dbc_id << " in LightParams.dbc" << std::endl; + + // failsafe, don't point to new id that couldn't be created + if (sky_param->_is_new_param_record) + lightDbRecord.write(LightDB::DataIDs + param_id, 0); } } - int light_float_start = lightParam_dbc_id * NUM_SkyFloatParamsNames - 5; - - for (int i = 0; i < NUM_SkyFloatParamsNames; ++i) + // save LightIntBand.dbc + if (sky_param->_colors_need_save || sky_param->_is_new_param_record) { - try + save_colors_dbc = true; + int light_int_start = lightParam_dbc_id * NUM_SkyColorNames - 17; + + for (int i = 0; i < NUM_SkyColorNames; ++i) { - DBCFile::Record rec = is_new_record ? gLightFloatBandDB.addRecord(light_float_start + i) : gLightFloatBandDB.getByID(light_float_start + i); - int entries = static_cast(skyParams[param_id]->floatParams[i].size()); - - rec.write(LightFloatBandDB::Entries, entries); // nb of entries - - // for (int l = 0; l < entries; l++) - for (int l = 0; l < 16; l++) + try { - if (l >= entries) + DBCFile::Record rec = sky_param->_is_new_param_record ? gLightIntBandDB.addRecord(light_int_start + i) + : gLightIntBandDB.getByID(light_int_start + i); + // int entries = rec.getInt(LightIntBandDB::Entries); + int entries = static_cast(sky_param->colorRows[i].size()); + + rec.write(LightIntBandDB::Entries, entries); // nb of entries + + for (int l = 0; l < 16; l++) { - rec.write(LightFloatBandDB::Times + l, 0); - rec.write(LightFloatBandDB::Values + l, 0.0f); - } - else - { - rec.write(LightFloatBandDB::Times + l, skyParams[param_id]->floatParams[i][l].time); - rec.write(LightFloatBandDB::Values + l, skyParams[param_id]->floatParams[i][l].value); + if (l >= entries) + { + rec.write(LightIntBandDB::Times + l, 0); + rec.write(LightIntBandDB::Values + l, 0); + } + else + { + rec.write(LightIntBandDB::Times + l, sky_param->colorRows[i][l].time); + + int rebuilt_color_int = static_cast(sky_param->colorRows[i][l].color.z * 255.0f) + + (static_cast(sky_param->colorRows[i][l].color.y * 255.0f) << 8) + + (static_cast(sky_param->colorRows[i][l].color.x * 255.0f) << 16); + rec.write(LightIntBandDB::Values + l, rebuilt_color_int); + } } + + } + catch (...) + { + assert(false); + LogError << "When trying to save sky colors, sky id : " << lightDbRecord.getInt(LightDB::ID) << std::endl; } } - catch (...) + } + + // save LightFloatBand.dbc + if (sky_param->_floats_need_save || sky_param->_is_new_param_record) + { + save_floats_dbc = true; + int light_float_start = lightParam_dbc_id * NUM_SkyFloatParamsNames - 5; + + for (int i = 0; i < NUM_SkyFloatParamsNames; ++i) { - LogError << "Error when trying to save sky float params, sky id : " << data.getInt(LightDB::ID) << std::endl; + try + { + DBCFile::Record rec = sky_param->_is_new_param_record ? gLightFloatBandDB.addRecord(light_float_start + i) + : gLightFloatBandDB.getByID(light_float_start + i); + int entries = static_cast(skyParams[param_id]->floatParams[i].size()); + + rec.write(LightFloatBandDB::Entries, entries); // nb of entries + + // for (int l = 0; l < entries; l++) + for (int l = 0; l < 16; l++) + { + if (l >= entries) + { + rec.write(LightFloatBandDB::Times + l, 0); + rec.write(LightFloatBandDB::Values + l, 0.0f); + } + else + { + rec.write(LightFloatBandDB::Times + l, skyParams[param_id]->floatParams[i][l].time); + rec.write(LightFloatBandDB::Values + l, skyParams[param_id]->floatParams[i][l].value); + } + } + + } + catch (...) + { + LogError << "Error when trying to save sky float params, sky id : " << lightDbRecord.getInt(LightDB::ID) << std::endl; + } } } - try - { - DBCFile::Record light_param = gLightParamsDB.getByID(lightParam_dbc_id); - - if (skybox.has_value()) // TODO skybox dbc - { - // light_param.write(LightParamsDB::skybox, TODO); - } - else - light_param.write(LightParamsDB::skybox, 0); - - light_param.write(LightParamsDB::highlightSky, int(skyParams[param_id]->highlight_sky())); - light_param.write(LightParamsDB::water_shallow_alpha, skyParams[param_id]->river_shallow_alpha()); - light_param.write(LightParamsDB::water_deep_alpha, skyParams[param_id]->river_deep_alpha()); - light_param.write(LightParamsDB::ocean_shallow_alpha, skyParams[param_id]->ocean_shallow_alpha()); - light_param.write(LightParamsDB::ocean_deep_alpha, skyParams[param_id]->ocean_deep_alpha()); - light_param.write(LightParamsDB::glow, skyParams[param_id]->glow()); - } - catch (DBCFile::NotFound) - { - assert(false); - LogError << "When trying to get the lightparams for the entry " << lightParam_dbc_id << " in LightParams.dbc" << std::endl; - } + sky_param->_need_save = false; + sky_param->_is_new_param_record = false; } gLightDB.save(); - gLightIntBandDB.save(); - gLightFloatBandDB.save(); - gLightParamsDB.save(); - gLightSkyboxDB.save(); - - // emit map_dbc_updated(); + if (save_colors_dbc) + gLightIntBandDB.save(); + if (save_colors_dbc) + gLightFloatBandDB.save(); + if (save_param_dbc) + gLightParamsDB.save(); is_new_record = false; } diff --git a/src/noggit/Sky.h b/src/noggit/Sky.h index 463241d5..74d1ba81 100755 --- a/src/noggit/Sky.h +++ b/src/noggit/Sky.h @@ -39,7 +39,7 @@ enum SkyFloatParamsNames { SKY_FOG_DISTANCE, SKY_FOG_MULTIPLIER, - SKY_CELESTIAL_FLOW, + SKY_CELESTIAL_GLOW, SKY_CLOUD_DENSITY, SKY_UNK_FLOAT_PARAM_4, SKY_UNK_FLOAT_PARAM_5, @@ -48,15 +48,26 @@ enum SkyFloatParamsNames enum SkyParamsNames { - SKY_PARAM_CLEAR, - SKY_PARAM_CLEAR_UNDERWATER, - SKY_PARAM_TORM, - SKY_PARAM_STORM_UNDERWATER, - SKY_PARAM_DEATH, - SKY_PARAM_UNK_1, - SKY_PARAM_UNK_2, - SKY_PARAM_UNK_3, - NUM_SkyParamsNames + SKY_PARAM_CLEAR, + SKY_PARAM_CLEAR_UNDERWATER, + SKY_PARAM_TORM, + SKY_PARAM_STORM_UNDERWATER, + SKY_PARAM_DEATH, + SKY_PARAM_UNK_1, + SKY_PARAM_UNK_2, + SKY_PARAM_UNK_3, + NUM_SkyParamsNames +}; + +enum SkyModelSkyBoxFlags +{ + LIGHT_SKYBOX_FULL_DAY = 0x1, // Full day Skybox: animation syncs with time of day (uses animation 0, time of day is just in percentage). + LIGHT_SKYBOX_COMBINE = 0x2, // Combine Procedural And Skybox : render stars, sun and moons and clouds as well + /* + 0x04 Procedural Fog Color Blend + 0x08 Force Sun-shafts + 0x10 Disable use Sun Fog Color + */ }; struct OutdoorLightStats @@ -161,19 +172,40 @@ struct SkyFloatParam int time; }; +// modern LightData.db +// unified timestamps for float and int data +struct LightData +{ + LightData(int paramId); + + unsigned int paramId; + unsigned int time = 0; + glm::vec3 colorRows[NUM_SkyColorNames] = {}; + float floatParams[NUM_SkyParamsNames] = {}; +}; + class SkyParam { public: std::optional skybox; + int skyboxFlags = 0; + int Id; SkyParam() = default; explicit SkyParam(int paramId, Noggit::NoggitRenderContext context); - std::vector colorRows[NUM_SkyColorNames]; // [NUM_SkyColorNames] // 36 + //array of 18 vectors(for each color), each vector item is a time/value + std::vector colorRows[NUM_SkyColorNames]; std::vector floatParams[NUM_SkyFloatParamsNames]; - int mmin[NUM_SkyColorNames]; // [NUM_SkyColorNames] // 36 - int mmin_float[NUM_SkyFloatParamsNames]; + + // first/min time value for each entry + // titi : deprecated those and replaced it by checking the time value of the first vector element + // int mmin[NUM_SkyColorNames]; + // int mmin_float[NUM_SkyFloatParamsNames]; + + // potential structure rework, more similar to retail/classic LightData.db + // std::vector lightData; bool highlight_sky() const { return _highlight_sky; } float river_shallow_alpha() const { return _river_shallow_alpha; } @@ -189,6 +221,13 @@ public: void set_ocean_shallow_alpha(float alpha) { _ocean_shallow_alpha = alpha; } void set_ocean_deep_alpha(float alpha) { _ocean_deep_alpha = alpha; } + // always save them for now + // later we can have a system to only save modified dbcs + bool _need_save = true; + bool _colors_need_save = true; + bool _floats_need_save = true; + bool _is_new_param_record = false; + private: // most common settings bool _highlight_sky = false; float _river_shallow_alpha = 0.5f; @@ -203,9 +242,11 @@ private: // most common settings class Sky { public: - std::optional skybox; + // std::optional skybox; int Id; + int mapId; // just for saving... + glm::vec3 pos = glm::vec3(0, 0, 0); float r1 = 0.f, r2 = 0.f; @@ -214,7 +255,7 @@ public: SkyParam* skyParams[NUM_SkyParamsNames]; int curr_sky_param = SKY_PARAM_CLEAR; - // std::string name; + std::string name; glm::vec3 colorFor(int r, int t) const; float floatParamFor(int r, int t) const; @@ -250,6 +291,7 @@ private: int cs = -1; ModelInstance stars; + bool _force_update = true; int _last_time = -1; glm::vec3 _last_pos; @@ -271,6 +313,8 @@ public: explicit Skies(unsigned int mapid, Noggit::NoggitRenderContext context); + Sky* createNewSky(Sky* old_sky, unsigned int new_id, glm::vec3& pos); + Sky* findSkyWeights(glm::vec3 pos); Sky* findClosestSkyByWeight(); @@ -323,6 +367,8 @@ public: void unload(); + void force_update() { _force_update = true; } + private: bool _uploaded = false; bool _need_color_buffer_update = true; diff --git a/src/noggit/rendering/WorldRender.cpp b/src/noggit/rendering/WorldRender.cpp index 57560234..0b6a8b4e 100755 --- a/src/noggit/rendering/WorldRender.cpp +++ b/src/noggit/rendering/WorldRender.cpp @@ -1038,7 +1038,8 @@ void WorldRender::draw (glm::mat4x4 const& model_view if (terrainMode == editing_mode::light) { - Sky* CurrentSky = skies()->findClosestSkyByDistance(camera_pos); + // Sky* CurrentSky = skies()->findClosestSkyByDistance(camera_pos); + Sky* CurrentSky = skies()->findClosestSkyByWeight(); if (!CurrentSky) return; @@ -1048,14 +1049,18 @@ void WorldRender::draw (glm::mat4x4 const& model_view const int CurrenTime = static_cast(_world->time) % MAX_TIME_VALUE_C; glCullFace(GL_FRONT); - for (Sky& sky : skies()->skies) + if (!draw_only_inside_light_sphere) { - if (CurrentSkyID > 1 && draw_only_inside_light_sphere) - break; + for (Sky& sky : skies()->skies) + { + // we draw the current sky below with glCullFace(GL_BACK); if (CurrentSkyID == sky.Id) continue; + if (sky.global) + continue; + if (glm::distance(sky.pos, camera_pos) <= _cull_distance) // TODO: frustum cull here { glm::vec4 diffuse = { sky.colorFor(LIGHT_GLOBAL_DIFFUSE, CurrenTime), 1.f }; @@ -1063,17 +1068,32 @@ void WorldRender::draw (glm::mat4x4 const& model_view _sphere_render.draw(mvp, sky.pos, ambient, sky.r1, 32, 18, alpha_light_sphere, false, draw_wireframe_light_sphere); _sphere_render.draw(mvp, sky.pos, diffuse, sky.r2, 32, 18, alpha_light_sphere, false, draw_wireframe_light_sphere); + + // TODO Those lines tank fps by 50% + // std::vector linePoints; + // linePoints.push_back(glm::vec3(sky.pos.x, sky.pos.y, sky.pos.z - sky.r2)); + // linePoints.push_back(glm::vec3(sky.pos.x, sky.pos.y, sky.pos.z + sky.r2)); + // _line_render.draw(mvp, linePoints, glm::vec4(1.f), false); } + } } glCullFace(GL_BACK); - if (CurrentSky && draw_only_inside_light_sphere) + if (CurrentSky && !CurrentSky->global) { glm::vec4 diffuse = { CurrentSky->colorFor(LIGHT_GLOBAL_DIFFUSE, CurrenTime), 1.f }; glm::vec4 ambient = { CurrentSky->colorFor(LIGHT_GLOBAL_AMBIENT, CurrenTime), 1.f }; - _sphere_render.draw(mvp, CurrentSky->pos, ambient, CurrentSky->r1, 32, 18, alpha_light_sphere, false, draw_wireframe_light_sphere); - _sphere_render.draw(mvp, CurrentSky->pos, diffuse, CurrentSky->r2, 32, 18, alpha_light_sphere, false, draw_wireframe_light_sphere); + // always render wireframe in the current light + // need to render outer first or it gets culled + _sphere_render.draw(mvp, CurrentSky->pos, diffuse, CurrentSky->r2, 32, 18, alpha_light_sphere, false, true); + _sphere_render.draw(mvp, CurrentSky->pos, ambient, CurrentSky->r1, 32, 18, alpha_light_sphere, false, true); + + + // std::vector linePoints; + // linePoints.push_back(glm::vec3(CurrentSky->pos.x, CurrentSky->pos.z, CurrentSky->pos.y - CurrentSky->r2)); + // linePoints.push_back(glm::vec3(CurrentSky->pos.x, CurrentSky->pos.z, CurrentSky->pos.y + CurrentSky->r2)); + // _line_render.draw(mvp, linePoints, glm::vec4(1.f, 0.f, 0.f, 1.f), false); } } } diff --git a/src/noggit/ui/tools/LightEditor/LightEditor.cpp b/src/noggit/ui/tools/LightEditor/LightEditor.cpp index 4af9aa5f..b8a9171b 100755 --- a/src/noggit/ui/tools/LightEditor/LightEditor.cpp +++ b/src/noggit/ui/tools/LightEditor/LightEditor.cpp @@ -23,34 +23,28 @@ LightEditor::LightEditor(MapView* map_view, QWidget* parent) , _map_view(map_view) , _world(map_view->getWorld()) { - // auto Skies = _map_view->getWorld()->renderer()->skies()->skies; - // Sky CurrSky = Skies[0]; - // get curent sky from camera position - // Sky* CurrSky = _map_view->getWorld()->renderer()->skies()->findSkyWeights(map_view->getCamera()->position); - setMinimumWidth(250); setMaximumWidth(250); - auto layout(new QVBoxLayout(this)); + auto layout = new QVBoxLayout(this); layout->setAlignment(Qt::AlignTop); - - - auto lightning_tabs = new QTabWidget(this); + lightning_tabs = new QTabWidget(this); layout->addWidget(lightning_tabs); - auto light_selection_widget = new QWidget(this); - light_selection_widget->setContentsMargins(0, 0, 0, 0); - auto light_selection_layout = new QFormLayout(light_selection_widget); // QFormLayout + // light select tab + auto light_selection_widget = new QWidget(lightning_tabs); + auto light_selection_layout = new QVBoxLayout(light_selection_widget); light_selection_layout->setContentsMargins(0, 0, 0, 0); - lightning_tabs->addTab(light_selection_widget, "Light Selection"); + // light edit tab + _light_editing_widget = new QWidget(lightning_tabs); + _light_editing_widget->setEnabled(false); + auto light_editing_layout = new QVBoxLayout(_light_editing_widget); + light_editing_layout->setContentsMargins(0, 0, 0, 0); + lightning_tabs->addTab(_light_editing_widget, "Edit Light"); - auto light_editing_widget = new QWidget(lightning_tabs); - light_editing_widget->setEnabled(false); - auto light_editing_layout = new QVBoxLayout(light_editing_widget); - lightning_tabs->addTab(light_editing_widget, "Edit Light"); // set time _world->time light_selection_layout->addWidget(new QLabel("Set current time :", this)); @@ -58,129 +52,163 @@ LightEditor::LightEditor(MapView* map_view, QWidget* parent) light_selection_layout->addWidget(time_dial); time_dial->setRange(0, 2880); // Time Values from 0 to 2880 where each number represents a half minute from midnight to midnight time_dial->setWrapping(true); - time_dial->setSliderPosition(0); // to get ingame orientation + time_dial->setSliderPosition((int)_world->time); // to get ingame orientation // time_value0_dial->setValue(color0.time); - time_dial->setInvertedAppearance(false); // sets the position at top + time_dial->setInvertedAppearance(true); // sets the position at top time_dial->setToolTip("Time (24hours)"); - time_dial->setSingleStep(360); // ticks are 360 units + time_dial->setSingleStep(360); // ticks are 360 units (1/8 = 3 hours) - QPushButton* GetCurrentSkyButton = new QPushButton("Edit current light", this); + QPushButton* GetCurrentSkyButton = new QPushButton("Edit current position's light", this); + GetCurrentSkyButton->setToolTip("Selection the highest weight light at camera's position"); + GetCurrentSkyButton->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::cog)); light_selection_layout->addWidget(GetCurrentSkyButton); + light_selection_layout->addWidget(new QLabel("Current Map Lights :", this)); - _light_tree = new QTreeWidget(); + _light_tree = new QListWidget(this); light_selection_layout->addWidget(_light_tree); - _light_tree->setHeaderLabel("Current map lights"); - _light_tree->setColumnCount(1); - // _light_tree->setMaximumHeight(400); // TODO : editing the height fucks up the layout + // _light_tree->setWindowTitle("Current map lights"); + _light_tree->setViewMode(QListView::ListMode); + _light_tree->setSelectionMode(QAbstractItemView::SingleSelection); + _light_tree->setSelectionBehavior(QAbstractItemView::SelectItems); + _light_tree->setFixedHeight(580); + _light_tree->setUniformItemSizes(true); - // for (auto& sky : _world->renderer()->skies()->skies) // bad idea, renderer needs to be loaded first + // for (auto& sky : _world->renderer()->skies()->skies) // renderer needs to be loaded first for (DBCFile::Iterator i = gLightDB.begin(); i != gLightDB.end(); ++i) { if (i->getInt(LightDB::Map) == _world->getMapID()) { - QTreeWidgetItem* item = new QTreeWidgetItem(); + QListWidgetItem* item = new QListWidgetItem(); std::stringstream ss; - auto light_id = i->getUInt(LightDB::ID); - item->setData(0, 0, QVariant(light_id) ); + unsigned int light_id = i->getUInt(LightDB::ID); + item->setData(Qt::UserRole + 1, QVariant(light_id) ); // when setting an icon (global light), it uses role 1 + + bool global = (i->getFloat(LightDB::PositionX) == 0.0f && i->getFloat(LightDB::PositionY) == 0.0f + && i->getFloat(LightDB::PositionZ) == 0.0f); std::string light_name = "Unamed Light"; if (light_names_map.contains(light_id)) light_name = light_names_map.at(light_id); - - else if (i->getFloat(LightDB::PositionX) == 0.0f && i->getFloat(LightDB::PositionY) == 0.0f && i->getFloat(LightDB::PositionZ) == 0.0f) + else if (global) light_name = "Global Light"; + if (global) + { + item->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::sun)); + } + ss << i->getUInt(LightDB::ID) << "-" << light_name;// gAreaDB.getAreaName(area_id); - item->setText(0, QString(ss.str().c_str()));// TODO : light names + item->setText(QString(ss.str().c_str()));// TODO : light names // if (global) - _light_tree->addTopLevelItem(item); + _light_tree->addItem(item); + + if (global) + { + _light_tree->setItemSelected(item, true); + } } } QPushButton* GetSelectedSkyButton = new QPushButton("Edit selected light", this); + GetSelectedSkyButton->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::cog)); light_selection_layout->addWidget(GetSelectedSkyButton); + QPushButton* addNewSkyButton = new QPushButton("(IN DEV) Duplicate selected(create new)", this); + addNewSkyButton->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::plus)); + light_selection_layout->addWidget(addNewSkyButton); + + QPushButton* deleteSkyButton = new QPushButton("(IN DEV) delete light", this); + deleteSkyButton->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::times)); + light_selection_layout->addWidget(deleteSkyButton); + + QPushButton* portToSkyButton = new QPushButton("(IN DEV) port to light", this); + portToSkyButton->setIcon(Noggit::Ui::FontAwesomeIcon(Noggit::Ui::FontAwesome::running)); + light_selection_layout->addWidget(portToSkyButton); + + light_selection_layout->addStretch(); // Add a stretch to prevent expansion + // global settings ********************************************************************************************** // // TODO : name lights on laoding instead light_editing_layout->addWidget(new QLabel("Selected Light :", this), 0); - auto lightid_label = new QLabel("No light selected", this); + lightid_label = new QLabel("No light selected", this); light_editing_layout->addWidget(lightid_label); - QPushButton* SaveCurrentSkyButton = new QPushButton("Save Light(Write DBCs)", this); - SaveCurrentSkyButton->setEnabled(false); - light_editing_layout->addWidget(SaveCurrentSkyButton); + save_current_sky_button = new QPushButton("Save Light(Write DBCs)", this); + save_current_sky_button->setEnabled(false); + light_editing_layout->addWidget(save_current_sky_button); QGroupBox* global_values_group = new QGroupBox("Global settings", this); // alpha_values_group->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); - auto global_values_layout = new QGridLayout(global_values_group); + // auto global_values_layout = new QGridLayout(global_values_group); + auto global_values_layout = new QFormLayout(global_values_group); - global_values_layout->addWidget(new QLabel("Name:", this), 0, 0); - auto name_line_edit = new QLineEdit(this); - global_values_layout->addWidget(name_line_edit, 0, 1); + name_line_edit = new QLineEdit(this); + name_line_edit->setDisabled(true); + global_values_layout->addRow("Name:", name_line_edit); - global_values_layout->addWidget(new QLabel("Position X:", this),1,0); - auto pos_x_spin = new QDoubleSpinBox(this); - pos_x_spin->setRange(-17066.66656 * 2, 17066.66656*2); // size = 17066.66656 + global_light_chk = new QCheckBox("Global Light", this); + global_light_chk->setToolTip("The map's global light will be used when the player isn't within any other light radius."); + global_light_chk->setDisabled(true); + global_values_layout->addRow(global_light_chk); + + pos_x_spin = new QDoubleSpinBox(this); + pos_x_spin->setRange(-17066.66656 * 2, 17066.66656 * 2); // size = 17066.66656 pos_x_spin->setValue(0); pos_x_spin->setSingleStep(50); pos_x_spin->setEnabled(false); - global_values_layout->addWidget(pos_x_spin,1,1); + global_values_layout->addRow("Position X:", pos_x_spin); - global_values_layout->addWidget(new QLabel("Position Y:", this),2,0); - auto pos_y_spin = new QDoubleSpinBox(this); - pos_y_spin->setRange(-17066.66656 * 2, 17066.66656*2); // size = 17066.66656 + pos_y_spin = new QDoubleSpinBox(this); + pos_y_spin->setRange(-17066.66656 * 2, 17066.66656 * 2); // size = 17066.66656 pos_y_spin->setValue(0); pos_y_spin->setSingleStep(50); pos_y_spin->setEnabled(false); - global_values_layout->addWidget(pos_y_spin,2,1); + global_values_layout->addRow("Position Y:", pos_y_spin); - global_values_layout->addWidget(new QLabel("Position Z:", this),3,0); - auto pos_z_spin = new QDoubleSpinBox(this); - pos_z_spin->setRange(-17066.66656 * 2, 17066.66656*2); // ???? + pos_z_spin = new QDoubleSpinBox(this); + pos_z_spin->setRange(-17066.66656 * 2, 17066.66656*2); // ???? highest seen in 3.3.5 is 33,360 pos_z_spin->setValue(0); pos_z_spin->setSingleStep(50); pos_z_spin->setEnabled(false); - global_values_layout->addWidget(pos_z_spin,3,1); + global_values_layout->addRow("Position Z:", pos_z_spin); - global_values_layout->addWidget(new QLabel("Inner Radius:", this),4,0); - auto inner_radius_spin = new QDoubleSpinBox(this); + inner_radius_spin = new QDoubleSpinBox(this); inner_radius_spin->setRange(0, 100000); // max seen in dbc is 3871 (139363 E36 ) inner_radius_spin->setValue(0); inner_radius_spin->setSingleStep(50); inner_radius_spin->setEnabled(false); - global_values_layout->addWidget(inner_radius_spin,4,1); + global_values_layout->addRow("Inner Radius:", inner_radius_spin); - global_values_layout->addWidget(new QLabel("Outer Radius:", this),5,0); - auto outer_radius_spin = new QDoubleSpinBox(this); + outer_radius_spin = new QDoubleSpinBox(this); outer_radius_spin->setRange(0, 100000); // max seen in dbc is 3871 (139363 E36 ) outer_radius_spin->setValue(0); outer_radius_spin->setSingleStep(50); outer_radius_spin->setEnabled(false); - global_values_layout->addWidget(outer_radius_spin,5,1); + global_values_layout->addRow("Outer Radius:", outer_radius_spin); light_editing_layout->addWidget(global_values_group); // BELOW IS PARAM SPECIFIC SETTINGS + auto warning_label = new QLabel("Warning : Can't currently change param id,\n changes will affect all users of this param"); + warning_label->setStyleSheet("QLabel { color : orange; }"); + light_editing_layout->addWidget(warning_label); + light_editing_layout->addWidget(new QLabel("Param Type :", this)); param_combobox = new QComboBox(this); param_combobox->setEnabled(false); light_editing_layout->addWidget(param_combobox); + // NUM_SkyParamsNames param_combobox->addItem("Clear Weather"); // Used in clear weather. param_combobox->addItem("Clear Weather Underwater"); // Used in clear weather while being underwater. param_combobox->addItem("Storm Weather"); // Used in rainy/snowy/sandstormy weather. param_combobox->addItem("Storm Weather Underwater"); // Used in rainy/snowy/sandstormy weather while being underwater. param_combobox->addItem("Death Effect"); // ParamsDeath. Only 4 and in newer ones 3 are used as value here (with some exceptions). Changing this seems to have no effect in 3.3.5a (is death light setting hardcoded?) - // param_combobox->addItem("Clear Weather"); - // param_combobox->addItem("Clear Weather"); - // param_combobox->addItem("Clear Weather"); - - // for (int i = 0; i < NUM_SkyParamsNames; ++i) - // { - // // auto sky_param = _curr_sky->skyParams[i]; - // } + param_combobox->addItem("unknown param 1"); + param_combobox->addItem("unknown param 2"); + param_combobox->addItem("unknown param 3"); QGroupBox* light_param_group = new QGroupBox("Light Params", this); light_editing_layout->addWidget(light_param_group); @@ -198,7 +226,7 @@ LightEditor::LightEditor(MapView* map_view, QWidget* parent) glow_slider->setRange(0, 100); // between 0 and 1, increases by 0.05. Multiplying everything by 100 cuz Qslider doesn't seem to support floats glow_slider->setTickInterval(5); glow_slider->setSingleStep(5); - glow_slider->setValue(100); + glow_slider->setValue(50); glow_slider->setEnabled(false); param_grid_layout->addWidget(glow_slider,0,1); @@ -213,6 +241,18 @@ LightEditor::LightEditor(MapView* map_view, QWidget* parent) skybox_model_lineedit->setEnabled(false); param_grid_layout->addWidget(skybox_model_lineedit, 2, 1); + skybox_flag_1 = new QCheckBox("Full day Skybox", this); + skybox_flag_1->setCheckState(Qt::Unchecked); + skybox_flag_1->setEnabled(false); + skybox_flag_1->setToolTip("animation syncs with time of day (uses animation 0, time of day is just in percentage)."); + param_grid_layout->addWidget(skybox_flag_1, 3, 0, 1, 2); + skybox_flag_2 = new QCheckBox("Combine Procedural And Skybox", this); + skybox_flag_2->setCheckState(Qt::Unchecked); + skybox_flag_2->setEnabled(false); + skybox_flag_2->setToolTip("render stars, sun and moons and clouds as well."); + param_grid_layout->addWidget(skybox_flag_2, 4, 0, 1, 2); + + // Alpha values ********************************************************************************************** // QGroupBox* alpha_values_group = new QGroupBox("Alpha Values", light_param_group); @@ -268,10 +308,15 @@ LightEditor::LightEditor(MapView* map_view, QWidget* parent) std::string color_name = sky_color_names_map.at(i); LightViewPreview* LightPrev = new LightViewPreview(QString("%1 Color").arg(color_name.c_str()), - QSize(150, LIGHT_VIEW_PREVIEW_HEIGHT)); + QSize(180, LIGHT_VIEW_PREVIEW_HEIGHT)); LightsPreview.push_back(LightPrev); color_values_layout->addWidget(LightPrev, i, 0); + int availableWidth = color_values_group->width() - color_values_layout->contentsMargins().left() + - color_values_layout->contentsMargins().right() - color_values_layout->spacing(); + int test_suggestedWidth = LightPrev->sizeHint().width(); + int test_suggestedWidth2 = LightPrev->minimumSizeHint().width(); + connect(LightPrev, &LightViewPreview::LeftClicked, [this, i, LightPrev]() { if (!_curr_sky) @@ -303,210 +348,338 @@ LightEditor::LightEditor(MapView* map_view, QWidget* parent) connect(time_dial, &QDial::valueChanged, [&](int v) // [this] { _map_view->getWorld()->time = v; - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); + _world->renderer()->skies()->force_update(); + UpdateWorldTime(); } ); connect(GetCurrentSkyButton, &QPushButton::clicked, [=]() { - // _curr_sky = _map_view->getWorld()->renderer()->skies()->findSkyWeights(map_view->getCamera()->position); - auto new_sky = _map_view->getWorld()->renderer()->skies()->findClosestSkyByWeight(); - if (_curr_sky == nullptr) + // Sky* new_sky = _map_view->getWorld()->renderer()->skies()->findSkyWeights(map_view->getCamera()->position); // this just returns the global sky + // Sky* new_sky = _map_view->getWorld()->renderer()->skies()->findClosestSkyByDistance(map_view->getCamera()->position); + Sky* new_sky = _map_view->getWorld()->renderer()->skies()->findClosestSkyByWeight(); + if (new_sky == nullptr) return; // todo error else - _curr_sky = new_sky; - - light_editing_widget->setEnabled(true); - lightning_tabs->setCurrentWidget(light_editing_widget); - - SaveCurrentSkyButton->setEnabled(true); - // maybe move the inits to a separate function - // global values - std::stringstream ss; - std::string light_name = "Unamed Light"; - if (light_names_map.contains(_curr_sky->Id)) - light_name = light_names_map.at(_curr_sky->Id); - else if (_curr_sky->global) - light_name = "Global Light"; - ss << _curr_sky->Id << "-" << light_name; - lightid_label->setText(QString::fromStdString(ss.str().c_str())); - - name_line_edit->setText(_curr_sky->name); - pos_x_spin->setValue(_curr_sky->pos.x); - pos_x_spin->setEnabled(true); - pos_y_spin->setValue(_curr_sky->pos.z); // swap Z and Y - pos_y_spin->setEnabled(true); - pos_z_spin->setValue(_curr_sky->pos.y); - pos_z_spin->setEnabled(true); - inner_radius_spin->setValue(_curr_sky->r1); - inner_radius_spin->setEnabled(true); - outer_radius_spin->setValue(_curr_sky->r2); - outer_radius_spin->setEnabled(true); - - param_combobox->setEnabled(true); - param_combobox->setCurrentIndex(0); - // light param specific data (only 0 currently) - auto default_param = _curr_sky->skyParams[param_combobox->currentIndex()]; - glow_slider->setSliderPosition(default_param->glow() * 100); - glow_slider->setEnabled(true); - highlight_sky_checkbox->setCheckState(Qt::CheckState(default_param->highlight_sky() ) ); - highlight_sky_checkbox->setEnabled(true); - if (_curr_sky->skybox.has_value()) - skybox_model_lineedit->setText(QString::fromStdString(default_param->skybox.value().model.get()->file_key().filepath())); - // alpha values - shallow_water_alpha_slider->setSliderPosition(default_param->river_shallow_alpha() * 100); // TODO bug : when reselecting the same light, sliders with digits values reset to 0. - shallow_water_alpha_slider->setEnabled(true); - deep_water_alpha_slider->setSliderPosition(default_param->river_deep_alpha() * 100); - deep_water_alpha_slider->setEnabled(true); - shallow_ocean_alpha_slider->setSliderPosition(default_param->ocean_shallow_alpha() * 100); - shallow_ocean_alpha_slider->setEnabled(true); - deep_ocean_alpha_slider->setSliderPosition(default_param->ocean_deep_alpha() * 100); - deep_ocean_alpha_slider->setEnabled(true); - // color values - for (int i = 0; i < NUM_SkyColorNames; ++i) { - - LightsPreview[i]->SetPreview(default_param->colorRows[i]); - - //for (int l = 0; l < default_param->colorRows[i]; ++) - //default_param->colorRows[i] - //_color_value_Buttons[i]->setText(QString::fromStdString(std::format("{} / 16 values", default_param->colorRows[i].size()))); - //_color_value_Buttons[i]->setEnabled(true); + loadSelectSky(new_sky); } - }); + + connect(GetSelectedSkyButton, &QPushButton::clicked, [=]() { - // TODO : load selected sky and teleport to it - // auto selecetd_light = _light_tree->selectedItems().data auto const& selected_items = _light_tree->selectedItems(); if (selected_items.size()) { - auto selected_light_id = selected_items.back()->data(0, 0).toInt(); // TODO : doesn't work since moving to role 0 + unsigned int selected_light_id = selected_items.back()->data(Qt::UserRole + 1).toUInt(); - for (int i = 0; i < _map_view->getWorld()->renderer()->skies()->skies.size(); i++) + for (Sky& sky : _map_view->getWorld()->renderer()->skies()->skies) { - auto &sky = _map_view->getWorld()->renderer()->skies()->skies[i]; if (sky.Id == selected_light_id) { - _curr_sky = &sky; - _map_view->_camera.position = _curr_sky->pos; - _map_view->_camera.position.z += 100; + loadSelectSky(&sky); + + // TODO : load tile and teleport where the light is at + // + // _map_view->_camera.position = _curr_sky->pos; + // _map_view->_camera.position.z += 100; // get terrain's height for Z axis. - // auto chunk = _world->getChunkAt(glm::vec3(_curr_sky->pos.x, _curr_sky->pos.y, _curr_sky->pos.z)); // need to load tile first ?? + // auto chunk = _world->getChunkAt(glm::vec3(_curr_sky->pos.x, _curr_sky->pos.y, _curr_sky->pos.z)); // need to load tile first // if (chunk != nullptr) - // _map_view->_camera.position.z = chunk->getMaxHeight() + 20.0f; - // TODO : initialise + // _map_view->_camera.position.z = chunk->getMaxHeight() + 20.0f; + // TODO : initialize + + return; } } } }); + + connect(_light_tree, &QListWidget::itemDoubleClicked, this, [=](QListWidgetItem* item) + { + unsigned int selected_light_id = item->data(Qt::UserRole + 1).toUInt(); + + for (Sky& sky : _map_view->getWorld()->renderer()->skies()->skies) + { + if (sky.Id == selected_light_id) + { + loadSelectSky(&sky); + + return; + } + } + }); + + + connect(addNewSkyButton, &QPushButton::clicked, [=]() { + + // TODO. when there is no light to duplicate we need create new function + + // _world->getRenderContext(); + + // get selected sky to duplicate + Sky* old_sky = nullptr; + + std::string old_name = ""; + + auto const& selected_items = _light_tree->selectedItems(); + if (selected_items.size()) + { + old_name = selected_items.back()->text().toStdString(); + unsigned int selected_light_id = selected_items.back()->data(Qt::UserRole + 1).toUInt(); + + for (Sky& sky : _map_view->getWorld()->renderer()->skies()->skies) + { + if (sky.Id == selected_light_id) + { + old_sky = &sky; + } + } + } + if (old_sky == nullptr) + return; + + if (old_sky->global) + { + QMessageBox::warning + (nullptr + , "Error" + , "You cannot duplicate a Global light. " + "There can only be one global light per map." + , QMessageBox::Ok + ); + } + + unsigned int new_light_id = gLightDB.getEmptyRecordID(LightDB::ID); + + // create new sky entry (duplicate) + Sky* new_sky = _map_view->getWorld()->renderer()->skies()->createNewSky(old_sky, new_light_id, _map_view->getCamera()->position); + + // add new item to tree + { + QListWidgetItem* item = new QListWidgetItem(); + + std::stringstream ss; + item->setData(Qt::UserRole + 1, QVariant(new_light_id)); // when setting an icon (global light), it uses role 1 + + std::string new_light_name = "Noggit Copy of " + old_name; + + ss << new_light_id << "-" << new_light_name; + item->setText(QString(ss.str().c_str())); + + _light_tree->addItem(item); + + _light_tree->setCurrentItem(item); + _light_tree->scrollToItem(item); + } + + // loadSelectSky(new_sky); + + }); + + connect(deleteSkyButton, &QPushButton::clicked, [=]() { + + }); + + connect(portToSkyButton, &QPushButton::clicked, [=]() { + + }); + connect(param_combobox, qOverload(&QComboBox::currentIndexChanged), [this](int index) { // update rendering to selected param - _curr_sky->curr_sky_param = index; - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky - - try - { - DBCFile::Record data = gLightDB.getByID(_curr_sky->Id); - int nb_user = 0; - for (DBCFile::Iterator i = gLightDB.begin(); i != gLightDB.end(); ++i) - { - for (int l = 0; l < NUM_SkyParamsNames; l++) - { - if (i->getInt(LightDB::DataIDs + l) == data.getInt(LightDB::DataIDs + index)) - nb_user++; - } - } - _nb_param_users->setText("This param is used " + nb_user); - - auto sky_param = _curr_sky->skyParams[index]; - - glow_slider->setSliderPosition(sky_param->glow() * 100); - highlight_sky_checkbox->setCheckState(Qt::CheckState(sky_param->highlight_sky())); - if (_curr_sky->skybox.has_value()) - skybox_model_lineedit->setText(QString::fromStdString(sky_param->skybox.value().model.get()->file_key().filepath())); - // alpha values - shallow_water_alpha_slider->setSliderPosition(sky_param->river_shallow_alpha() * 100); - deep_water_alpha_slider->setSliderPosition(sky_param->river_deep_alpha() * 100); - shallow_ocean_alpha_slider->setSliderPosition(sky_param->ocean_shallow_alpha() * 100); - deep_ocean_alpha_slider->setSliderPosition(sky_param->ocean_deep_alpha() * 100); - // color values - for (int i = 0; i < NUM_SkyColorNames; ++i) - { - LightsPreview[i]->SetPreview(sky_param->colorRows[i]); - //_color_value_Buttons[i]->setText(QString::fromStdString(std::format("{} / 16 values", sky_param->colorRows[i].size()))); - } - } - catch (LightDB::NotFound) + if (!_curr_sky) { assert(false); + return; } + if (!_curr_sky->skyParams[index]) + return; + + _curr_sky->curr_sky_param = index; + _world->renderer()->skies()->force_update(); + + load_light_param(index); + }); - connect(SaveCurrentSkyButton, &QPushButton::clicked, [=]() { + connect(save_current_sky_button, &QPushButton::clicked, [=]() { _curr_sky->save_to_dbc(); }); connect(pos_x_spin, qOverload(&QDoubleSpinBox::valueChanged), [&](double v) { _curr_sky->pos.x = v; // pos_x_spin->value(); - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky + _world->renderer()->skies()->force_update(); }); connect(pos_y_spin, qOverload(&QDoubleSpinBox::valueChanged), [&](double v) { _curr_sky->pos.z = v; // pos_y_spin->value(); - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky + _world->renderer()->skies()->force_update(); }); connect(pos_z_spin, qOverload(&QDoubleSpinBox::valueChanged), [&](double v) { _curr_sky->pos.y = v; // pos_z_spin->value(); - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky + _world->renderer()->skies()->force_update(); }); connect(inner_radius_spin, qOverload(&QDoubleSpinBox::valueChanged), [&](double v) { _curr_sky->r1 = v; // inner_radius_spin->value(); - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky + _world->renderer()->skies()->force_update(); }); connect(outer_radius_spin, qOverload(&QDoubleSpinBox::valueChanged), [&](double v) { _curr_sky->r2 = v; // outer_radius_spin->value(); - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky + _world->renderer()->skies()->force_update(); }); connect(glow_slider, &QSlider::valueChanged, [&](int v) { - _curr_sky->skyParams[param_combobox->currentIndex()]->set_glow(v / 100); // glow_slider->value() / 100; // crashes, glow_slider is null. - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky + _curr_sky->skyParams[param_combobox->currentIndex()]->set_glow(v / 100); + _world->renderer()->skies()->force_update(); }); connect(highlight_sky_checkbox, &QCheckBox::stateChanged, [&](int state) { _curr_sky->skyParams[param_combobox->currentIndex()]->set_highlight_sky(state); - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky + _world->renderer()->skies()->force_update(); }); connect(shallow_water_alpha_slider, &QSlider::valueChanged, [&](int v) { _curr_sky->skyParams[param_combobox->currentIndex()]->set_river_shallow_alpha(v / 100); - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky + _world->renderer()->skies()->force_update(); }); connect(deep_water_alpha_slider, &QSlider::valueChanged, [&](int v) { _curr_sky->skyParams[param_combobox->currentIndex()]->set_river_deep_alpha(v / 100); - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky + _world->renderer()->skies()->force_update(); }); connect(shallow_ocean_alpha_slider, &QSlider::valueChanged, [&](int v) { _curr_sky->skyParams[param_combobox->currentIndex()]->set_ocean_shallow_alpha(v / 100); - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky + _world->renderer()->skies()->force_update(); }); connect(deep_ocean_alpha_slider, &QSlider::valueChanged, [&](int v) { _curr_sky->skyParams[param_combobox->currentIndex()]->set_ocean_deep_alpha(v / 100); - _world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast(_world->time) % 2880); // find how to update sky + _world->renderer()->skies()->force_update(); }); + // connect(skybox_model_lineedit, &QLineEdit::textChanged, [&](std::string v) { + QLineEdit::connect(skybox_model_lineedit, &QLineEdit::textChanged + , [=] + { + auto text = skybox_model_lineedit->text().toStdString(); + if (text.empty()) + _curr_sky->skyParams[param_combobox->currentIndex()]->skybox.reset(); + else + _curr_sky->skyParams[param_combobox->currentIndex()]->skybox.emplace(text.c_str(), _world->getRenderContext()); + + _world->renderer()->skies()->force_update(); + }); + + connect(skybox_flag_1, &QCheckBox::stateChanged, [&](int state) { + if (state) // set bit + _curr_sky->skyParams[param_combobox->currentIndex()]->skyboxFlags |= (1 << (0)); + else // remove bit + _curr_sky->skyParams[param_combobox->currentIndex()]->skyboxFlags &= ~(1 << (0)); + }); + + connect(skybox_flag_2, &QCheckBox::stateChanged, [&](int state) { + if (state) // set bit + _curr_sky->skyParams[param_combobox->currentIndex()]->skyboxFlags |= (1 << (1)); + else // remove bit + _curr_sky->skyParams[param_combobox->currentIndex()]->skyboxFlags &= ~(1 << (1)); + }); + + // connect(floats_editor_button, &QPushButton::clicked, [=]() { + // LightFloatsEditor * Editor = new LightFloatsEditor(_map_view, _curr_sky->skyParams[param_combobox->currentIndex()], this); + // + // Editor->show(); + // ); + +} + +void LightEditor::loadSelectSky(Sky* sky) +{ + QSignalBlocker const _1(pos_x_spin); + QSignalBlocker const _2(pos_y_spin); + QSignalBlocker const _3(pos_z_spin); + QSignalBlocker const _4(inner_radius_spin); + QSignalBlocker const _5(outer_radius_spin); + + _curr_sky = sky; + + // disable combobox param items if param is not set or doesn't exist + // in the future allow to add/edit param id + for (int i = 0; i < NUM_SkyParamsNames; ++i) + { + auto sky_param = _curr_sky->skyParams[i]; + if (!sky_param) + { + QStandardItemModel* model = qobject_cast(param_combobox->model()); + + if (model) { + QStandardItem* item = model->item(i); + if (item) { + item->setFlags(item->flags() & ~Qt::ItemIsEnabled); + } + } + } + } + + _light_editing_widget->setEnabled(true); + lightning_tabs->setCurrentWidget(_light_editing_widget); + + save_current_sky_button->setEnabled(true); + // maybe move the inits to a separate function + // global values + std::stringstream ss; + std::string light_name = "Unamed Light"; + if (light_names_map.contains(_curr_sky->Id)) + light_name = light_names_map.at(_curr_sky->Id); + else if (_curr_sky->global) + light_name = "Global Light"; + ss << _curr_sky->Id << "-" << light_name; + lightid_label->setText(QString::fromStdString(ss.str().c_str())); + + // name_line_edit->setText(QString::fromStdString(_curr_sky->name)); + name_line_edit->setText(QString::fromStdString(light_name)); + + if (_curr_sky->global) + { + global_light_chk->setChecked(true); + pos_x_spin->setEnabled(false); + pos_y_spin->setEnabled(false); + pos_z_spin->setEnabled(false); + inner_radius_spin->setEnabled(false); + outer_radius_spin->setEnabled(false); + } + else + { + global_light_chk->setChecked(false); + pos_x_spin->setEnabled(true); + pos_y_spin->setEnabled(true); + pos_z_spin->setEnabled(true); + inner_radius_spin->setEnabled(true); + outer_radius_spin->setEnabled(true); + } + + pos_x_spin->setValue(_curr_sky->pos.x); + pos_y_spin->setValue(_curr_sky->pos.z); // swap Z and Y + pos_z_spin->setValue(_curr_sky->pos.y); + inner_radius_spin->setValue(_curr_sky->r1); + outer_radius_spin->setValue(_curr_sky->r2); + + param_combobox->setEnabled(true); + + { + QSignalBlocker const __(param_combobox); + param_combobox->setCurrentIndex(_curr_sky->curr_sky_param); + } + + load_light_param(param_combobox->currentIndex()); } void LightEditor::UpdateWorldTime() @@ -518,9 +691,95 @@ void LightEditor::UpdateWorldTime() ActiveEditor[i]->UpdateWorldTime(); } -void LightEditor::load_light_param() +void LightEditor::load_light_param(int param_id) { - // _radius_slider->setValue(radius); + if (!_curr_sky) + { + assert(false); + return; + } + + if (!_curr_sky->skyParams[param_id]) + return; + + // _curr_sky->curr_sky_param = param_id; + // _world->renderer()->skies()->force_update(); + + QSignalBlocker const _1(glow_slider); + QSignalBlocker const _2(highlight_sky_checkbox); + QSignalBlocker const _3(shallow_water_alpha_slider); + QSignalBlocker const _4(deep_water_alpha_slider); + QSignalBlocker const _5(shallow_ocean_alpha_slider); + QSignalBlocker const _6(deep_ocean_alpha_slider); + + QSignalBlocker const _7(skybox_model_lineedit); + QSignalBlocker const _8(skybox_flag_1); + QSignalBlocker const _9(skybox_flag_2); + + auto sky_param = _curr_sky->skyParams[param_combobox->currentIndex()]; + + int nb_user = 0; + try + { + DBCFile::Record data = gLightDB.getByID(_curr_sky->Id); + + for (DBCFile::Iterator i = gLightDB.begin(); i != gLightDB.end(); ++i) + { + for (int l = 0; l < NUM_SkyParamsNames; l++) + { + if (i->getInt(LightDB::DataIDs + l) == data.getInt(LightDB::DataIDs + param_combobox->currentIndex())) + nb_user++; + } + } + } + catch (...) + { + + } + + std::stringstream ss; + ss << "LightParam Id : " << sky_param->Id << "\nThis param is used " << nb_user << " times."; + _nb_param_users->setText(QString::fromStdString(ss.str().c_str())); + + glow_slider->setSliderPosition(sky_param->glow() * 100); + glow_slider->setEnabled(true); + highlight_sky_checkbox->setCheckState(Qt::CheckState(sky_param->highlight_sky())); + highlight_sky_checkbox->setEnabled(true); + // alpha values + shallow_water_alpha_slider->setSliderPosition(sky_param->river_shallow_alpha() * 100); + shallow_water_alpha_slider->setEnabled(true); + deep_water_alpha_slider->setSliderPosition(sky_param->river_deep_alpha() * 100); + deep_water_alpha_slider->setEnabled(true); + shallow_ocean_alpha_slider->setSliderPosition(sky_param->ocean_shallow_alpha() * 100); + shallow_ocean_alpha_slider->setEnabled(true); + deep_ocean_alpha_slider->setSliderPosition(sky_param->ocean_deep_alpha() * 100); + deep_ocean_alpha_slider->setEnabled(true); + // color values + for (int i = 0; i < NUM_SkyColorNames; ++i) + { + LightsPreview[i]->SetPreview(sky_param->colorRows[i]); + //_color_value_Buttons[i]->setText(QString::fromStdString(std::format("{} / 16 values", sky_param->colorRows[i].size()))); + } + + // skybox + skybox_model_lineedit->setText(""); + if (sky_param->skybox.has_value()) + { + skybox_model_lineedit->setText(QString::fromStdString(sky_param->skybox.value().model.get()->file_key().filepath())); + } + skybox_model_lineedit->setEnabled(true); + + skybox_flag_1->setChecked(false); + skybox_flag_2->setChecked(false); + + if (sky_param->skyboxFlags & (1 << 0)) + skybox_flag_1->setChecked(true); + + if (sky_param->skyboxFlags & (1 << 1)) + skybox_flag_1->setChecked(true); + + skybox_flag_1->setEnabled(true); + skybox_flag_2->setEnabled(true); } diff --git a/src/noggit/ui/tools/LightEditor/LightEditor.hpp b/src/noggit/ui/tools/LightEditor/LightEditor.hpp index 9745e644..d2300464 100755 --- a/src/noggit/ui/tools/LightEditor/LightEditor.hpp +++ b/src/noggit/ui/tools/LightEditor/LightEditor.hpp @@ -7,6 +7,7 @@ #include #include #include +#include namespace Noggit::Ui::Tools { @@ -23,7 +24,7 @@ namespace Noggit::Ui::Tools {8 , "Sun"}, {9 , "Cloud Sun"}, {10 , "Cloud Emissive"}, - {11 , "Cloud Layer 1 Ambian"}, + {11 , "Cloud Layer 1 Ambiant"}, {12 , "Cloud Layer 2 Ambiant"}, {13 , "Unknown/Unused"}, {14 , "Ocean Close"}, @@ -32,6 +33,15 @@ namespace Noggit::Ui::Tools {17 , "River Far"} }; + static const std::map sky_float_values_names_map = { + {0 , "Fog Distance"}, + {1 , "Fog Multiplier"}, + {2 , "Celestial Glow Through"}, + {3 , "Cloud Density"}, + {4 , "Unkown/Unused1"}, + {5 , "Unkown/Unused2"} + }; + // TODO : move to definitions files static const std::unordered_map light_names_map = { {1 , "Global Light"}, @@ -278,6 +288,7 @@ namespace Noggit::Ui::Tools { public: LightEditor(MapView* map_view, QWidget* parent = nullptr); + void UpdateWorldTime(); private: @@ -290,12 +301,30 @@ namespace Noggit::Ui::Tools std::vector LightsPreview; std::vector ActiveEditor; + QWidget* _light_editing_widget; + + QTabWidget* lightning_tabs; + QPushButton* save_current_sky_button; + QLabel* lightid_label; + + QCheckBox* global_light_chk; + QLineEdit* name_line_edit; + QDoubleSpinBox* pos_x_spin; + QDoubleSpinBox* pos_y_spin; + QDoubleSpinBox* pos_z_spin; + QDoubleSpinBox* inner_radius_spin; + QDoubleSpinBox* outer_radius_spin; + QLabel* _nb_param_users; - QTreeWidget* _light_tree; + QListWidget* _light_tree; QComboBox* param_combobox; QSlider* glow_slider; QCheckBox* highlight_sky_checkbox; + QLineEdit* skybox_model_lineedit; + QCheckBox* skybox_flag_1; + QCheckBox* skybox_flag_2; + QSlider* shallow_water_alpha_slider; QSlider* deep_water_alpha_slider; QSlider* shallow_ocean_alpha_slider; @@ -303,7 +332,8 @@ namespace Noggit::Ui::Tools bool _is_new_record = false; - void load_light_param(); + void load_light_param(int param_id); + void loadSelectSky(Sky* sky); }; diff --git a/src/noggit/ui/widgets/LightViewWidget.cpp b/src/noggit/ui/widgets/LightViewWidget.cpp index f5342b82..ebd02bbf 100644 --- a/src/noggit/ui/widgets/LightViewWidget.cpp +++ b/src/noggit/ui/widgets/LightViewWidget.cpp @@ -66,6 +66,8 @@ LightViewPreview::LightViewPreview(QString LightName, QSize Size, QWidget* paren : DynamicMouseWidget(parent), MainLayout(new QVBoxLayout(this)), Name(new QLabel(this)), Preview(new LightViewPixmap(Size, this)) { + // Preview->ShowLines(true); + Name->setText(LightName); MainLayout->addWidget(Name); @@ -245,12 +247,41 @@ bool LightViewPixmap::DrawLines() QPixmap ResultPixmap = QPixmap(Final.size()); QPainter Painter(&ResultPixmap); + + const bool blend_lines = false; for (int i = 0; i < Data.size(); ++i) { for (int y = 0; y < LIGHT_VIEW_PREVIEW_LINE_SIZE; ++y) { int X = Data[i].time * Final.width() / MAX_TIME_VALUE - LIGHT_VIEW_PREVIEW_LINE_SIZE / 2 + y; - Final = LightViewWidget::FillImagePart(Final, X, QColor(LIGHT_VIEW_PREVIEW_LINE_COLOR)); + if (!blend_lines) + { + Final = LightViewWidget::FillImagePart(Final, X, QColor(LIGHT_VIEW_PREVIEW_LINE_COLOR)); + continue; + } + + // blend the line instead, it just looks better with red. + if (X == Image.width() || X < 0) + continue; + + QColor new_color(255, 0, 0, 150); + + for (int Y = 0; Y < Image.height(); ++Y) + { + QColor existingColor = Image.pixelColor(X, Y); + QColor blendedColor; + + float alpha = new_color.alphaF(); + + // Blend the colors + int red = static_cast(new_color.red() * alpha + existingColor.red() * (1.0 - alpha)); + int green = static_cast(new_color.green() * alpha + existingColor.green() * (1.0 - alpha)); + int blue = static_cast(new_color.blue() * alpha + existingColor.blue() * (1.0 - alpha)); + + blendedColor.setRgb(red, green, blue); + Image.setPixelColor(QPoint(X, Y), blendedColor); + } + Final = Image; } } @@ -458,7 +489,7 @@ void LightViewEditor::closeEvent(QCloseEvent* event) void LightViewEditor::UpdateSkyColorRowsValue() { UpdateWidgetEdition(CurrentIndex); - _World->renderer()->skies()->update_sky_colors(_Map->getCamera()->position, static_cast(_World->time) % MAX_TIME_VALUE); + _World->renderer()->skies()->force_update(); Arrow->UpdateData(_Sky->colorRows[_eSkyColorIndex]); Preview->SetPreview(_Sky->colorRows[_eSkyColorIndex]);