Light editor updates WIP

This commit is contained in:
T1ti
2024-08-30 21:29:33 +02:00
parent d31a76009b
commit 3f62034c40
7 changed files with 844 additions and 342 deletions

View File

@@ -4505,6 +4505,7 @@ void MapView::tick (float dt)
_world->time += this->mTimespeed * dt;
_world->animtime += dt * 1000.0f;
if (mTimespeed > 0.0f)
lightEditor->UpdateWorldTime();
if (_draw_model_animations.get())

View File

@@ -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; i<NUM_SkyColorNames; ++i)
for (int i = 0; i < NUM_SkyColorNames; ++i)
{
if ((sky.colorFor(i, time).x>1.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;
auto& model = sky.skybox.value();
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.skyParams[sky.curr_sky_param]->skybox.value();
model.model->trans = sky.weight;
model.pos = camera_pos;
model.scale = 0.1f;
@@ -612,11 +660,17 @@ bool Skies::draw(glm::mat4x4 const& model_view
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,44 +986,117 @@ 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;
// save lightparams.dbc
if (sky_param->_need_save || sky_param->_is_new_param_record)
{
save_param_dbc = true;
try
{
DBCFile::Record light_param = sky_param->_is_new_param_record ? gLightParamsDB.addRecord(lightParam_dbc_id)
: gLightParamsDB.getByID(lightParam_dbc_id);
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());
if (sky_param->skybox.has_value()) // TODO skybox dbc
{
// try to find an existing record with those params
bool exists = false;
for (DBCFile::Iterator i = gLightSkyboxDB.begin(); i != gLightSkyboxDB.end(); ++i)
{
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;
}
}
if (!exists) // doesn't exist, create a new record
{
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 (DBCFile::NotFound)
{
assert(false);
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);
}
}
// save LightIntBand.dbc
if (sky_param->_colors_need_save || sky_param->_is_new_param_record)
{
save_colors_dbc = true;
int light_int_start = lightParam_dbc_id * NUM_SkyColorNames - 17;
for (int i = 0; i < NUM_SkyColorNames; ++i)
{
try
{
DBCFile::Record rec = is_new_record ? gLightIntBandDB.addRecord(light_int_start + i) : gLightIntBandDB.getByID(light_int_start + i);
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<int>(skyParams[param_id]->colorRows[i].size());
int entries = static_cast<int>(sky_param->colorRows[i].size());
rec.write(LightIntBandDB::Entries, entries); // nb of entries
@@ -982,29 +1109,36 @@ void Sky::save_to_dbc()
}
else
{
rec.write(LightIntBandDB::Times + l, skyParams[param_id]->colorRows[i][l].time);
rec.write(LightIntBandDB::Times + l, sky_param->colorRows[i][l].time);
int rebuilt_color_int = static_cast<int>(skyParams[param_id]->colorRows[i][l].color.z * 255.0f)
+ (static_cast<int>(skyParams[param_id]->colorRows[i][l].color.y * 255.0f) << 8)
+ (static_cast<int>(skyParams[param_id]->colorRows[i][l].color.x * 255.0f) << 16);
int rebuilt_color_int = static_cast<int>(sky_param->colorRows[i][l].color.z * 255.0f)
+ (static_cast<int>(sky_param->colorRows[i][l].color.y * 255.0f) << 8)
+ (static_cast<int>(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 : " << data.getInt(LightDB::ID) << std::endl;
LogError << "When trying to save sky colors, sky id : " << lightDbRecord.getInt(LightDB::ID) << std::endl;
}
}
}
// 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)
{
try
{
DBCFile::Record rec = is_new_record ? gLightFloatBandDB.addRecord(light_float_start + i) : gLightFloatBandDB.getByID(light_float_start + i);
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<int>(skyParams[param_id]->floatParams[i].size());
rec.write(LightFloatBandDB::Entries, entries); // nb of entries
@@ -1023,45 +1157,26 @@ void Sky::save_to_dbc()
rec.write(LightFloatBandDB::Values + l, skyParams[param_id]->floatParams[i][l].value);
}
}
}
catch (...)
{
LogError << "Error when trying to save sky float params, sky id : " << data.getInt(LightDB::ID) << std::endl;
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();
if (save_colors_dbc)
gLightIntBandDB.save();
if (save_colors_dbc)
gLightFloatBandDB.save();
if (save_param_dbc)
gLightParamsDB.save();
gLightSkyboxDB.save();
// emit map_dbc_updated();
is_new_record = false;
}

View File

@@ -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,
@@ -59,6 +59,17 @@ enum SkyParamsNames
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
{
float nightIntensity;
@@ -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<ModelInstance> skybox;
int skyboxFlags = 0;
int Id;
SkyParam() = default;
explicit SkyParam(int paramId, Noggit::NoggitRenderContext context);
std::vector<SkyColor> colorRows[NUM_SkyColorNames]; // [NUM_SkyColorNames] // 36
//array of 18 vectors(for each color), each vector item is a time/value
std::vector<SkyColor> colorRows[NUM_SkyColorNames];
std::vector<SkyFloatParam> 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> 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<ModelInstance> skybox;
// std::optional<ModelInstance> 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;

View File

@@ -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<int>(_world->time) % MAX_TIME_VALUE_C;
glCullFace(GL_FRONT);
if (!draw_only_inside_light_sphere)
{
for (Sky& sky : skies()->skies)
{
if (CurrentSkyID > 1 && draw_only_inside_light_sphere)
break;
// 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<glm::vec3> 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<glm::vec3> 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);
}
}
}

View File

@@ -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 = <20>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 = <20>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 = <20>17066.66656
pos_y_spin = new QDoubleSpinBox(this);
pos_y_spin->setRange(-17066.66656 * 2, 17066.66656 * 2); // size = <20>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 <20>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 <20>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,23 +348,291 @@ 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<int>(_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;
{
loadSelectSky(new_sky);
}
});
light_editing_widget->setEnabled(true);
lightning_tabs->setCurrentWidget(light_editing_widget);
SaveCurrentSkyButton->setEnabled(true);
connect(GetSelectedSkyButton, &QPushButton::clicked, [=]() {
auto const& selected_items = _light_tree->selectedItems();
if (selected_items.size())
{
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)
{
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
// if (chunk != nullptr)
// _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<int>(&QComboBox::currentIndexChanged), [this](int index) {
// update rendering to selected param
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(save_current_sky_button, &QPushButton::clicked, [=]() {
_curr_sky->save_to_dbc();
});
connect(pos_x_spin, qOverload<double>(&QDoubleSpinBox::valueChanged), [&](double v) {
_curr_sky->pos.x = v; // pos_x_spin->value();
_world->renderer()->skies()->force_update();
});
connect(pos_y_spin, qOverload<double>(&QDoubleSpinBox::valueChanged), [&](double v) {
_curr_sky->pos.z = v; // pos_y_spin->value();
_world->renderer()->skies()->force_update();
});
connect(pos_z_spin, qOverload<double>(&QDoubleSpinBox::valueChanged), [&](double v) {
_curr_sky->pos.y = v; // pos_z_spin->value();
_world->renderer()->skies()->force_update();
});
connect(inner_radius_spin, qOverload<double>(&QDoubleSpinBox::valueChanged), [&](double v) {
_curr_sky->r1 = v; // inner_radius_spin->value();
_world->renderer()->skies()->force_update();
});
connect(outer_radius_spin, qOverload<double>(&QDoubleSpinBox::valueChanged), [&](double v) {
_curr_sky->r2 = v; // outer_radius_spin->value();
_world->renderer()->skies()->force_update();
});
connect(glow_slider, &QSlider::valueChanged, [&](int v) {
_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()->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()->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()->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()->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()->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<QStandardItemModel*>(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;
@@ -331,182 +644,42 @@ LightEditor::LightEditor(MapView* map_view, QWidget* parent)
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);
// 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->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);
}
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);
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);
QSignalBlocker const __(param_combobox);
param_combobox->setCurrentIndex(_curr_sky->curr_sky_param);
}
});
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
for (int i = 0; i < _map_view->getWorld()->renderer()->skies()->skies.size(); i++)
{
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;
// 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 ??
// if (chunk != nullptr)
// _map_view->_camera.position.z = chunk->getMaxHeight() + 20.0f;
// TODO : initialise
}
}
}
});
connect(param_combobox, qOverload<int>(&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<int>(_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)
{
assert(false);
}
});
connect(SaveCurrentSkyButton, &QPushButton::clicked, [=]() {
_curr_sky->save_to_dbc();
});
connect(pos_x_spin, qOverload<double>(&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<int>(_world->time) % 2880); // find how to update sky
});
connect(pos_y_spin, qOverload<double>(&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<int>(_world->time) % 2880); // find how to update sky
});
connect(pos_z_spin, qOverload<double>(&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<int>(_world->time) % 2880); // find how to update sky
});
connect(inner_radius_spin, qOverload<double>(&QDoubleSpinBox::valueChanged), [&](double v) {
_curr_sky->r1 = v; // inner_radius_spin->value();
_world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast<int>(_world->time) % 2880); // find how to update sky
});
connect(outer_radius_spin, qOverload<double>(&QDoubleSpinBox::valueChanged), [&](double v) {
_curr_sky->r2 = v; // outer_radius_spin->value();
_world->renderer()->skies()->update_sky_colors(_map_view->getCamera()->position, static_cast<int>(_world->time) % 2880); // find how to update sky
});
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<int>(_world->time) % 2880); // find how to update sky
});
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<int>(_world->time) % 2880); // find how to update sky
});
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<int>(_world->time) % 2880); // find how to update sky
});
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<int>(_world->time) % 2880); // find how to update sky
});
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<int>(_world->time) % 2880); // find how to update sky
});
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<int>(_world->time) % 2880); // find how to update sky
});
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);
}

View File

@@ -7,6 +7,7 @@
#include <noggit/MapView.h>
#include <QtWidgets/qtreewidget.h>
#include <noggit/ui/widgets/LightViewWidget.h>
#include <QTabWidget>
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 <int, std::string> 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 <int, std::string> 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<LightViewPreview*> LightsPreview;
std::vector<LightViewEditor*> 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);
};

View File

@@ -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;
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<int>(new_color.red() * alpha + existingColor.red() * (1.0 - alpha));
int green = static_cast<int>(new_color.green() * alpha + existingColor.green() * (1.0 - alpha));
int blue = static_cast<int>(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<int>(_World->time) % MAX_TIME_VALUE);
_World->renderer()->skies()->force_update();
Arrow->UpdateData(_Sky->colorRows[_eSkyColorIndex]);
Preview->SetPreview(_Sky->colorRows[_eSkyColorIndex]);