World environment

This commit is contained in:
tovjemam 2026-05-19 19:11:53 +02:00
parent e9fc95a42b
commit cf8742c4fe
22 changed files with 495 additions and 39 deletions

View File

@ -90,6 +90,8 @@ set(CLIENT_ONLY_SOURCES
"src/gameview/skinning_ubo.cpp" "src/gameview/skinning_ubo.cpp"
"src/gameview/vehicleview.hpp" "src/gameview/vehicleview.hpp"
"src/gameview/vehicleview.cpp" "src/gameview/vehicleview.cpp"
"src/gameview/worldenv.hpp"
"src/gameview/worldenv.cpp"
"src/gameview/worldview.hpp" "src/gameview/worldview.hpp"
"src/gameview/worldview.cpp" "src/gameview/worldview.cpp"
"src/gfx/buffer_object.cpp" "src/gfx/buffer_object.cpp"

View File

@ -107,6 +107,11 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
{ {
CLIENT_ONLY(sflags |= gfx::SF_OBJECT_COLOR;) CLIENT_ONLY(sflags |= gfx::SF_OBJECT_COLOR;)
} }
else if (flag == "+ocolor_mult")
{
CLIENT_ONLY(sflags |= gfx::SF_OBJECT_COLOR;)
CLIENT_ONLY(sflags |= gfx::SF_OBJECT_COLOR_MULT;)
}
else if (flag == "+blend") else if (flag == "+blend")
{ {
std::string blend_str; std::string blend_str;
@ -118,6 +123,10 @@ std::shared_ptr<const assets::Model> assets::Model::LoadFromFile(const std::stri
sflags |= gfx::SF_BLEND_ADDITIVE; sflags |= gfx::SF_BLEND_ADDITIVE;
) )
} }
else if (flag == "+unlit")
{
CLIENT_ONLY(sflags |= gfx::SF_UNLIT;)
}
} }
CLIENT_ONLY( CLIENT_ONLY(

View File

@ -78,6 +78,16 @@ game::OpenWorld::OpenWorld() : EnterableWorld("openworld")
}); });
} }
daytime_offset_ = static_cast<float>(rand() % 24);
}
void game::OpenWorld::Update(int64_t delta_time)
{
Super::Update(delta_time);
const float timespeed = 0.05f;
SetDayTime(static_cast<float>(GetTime()) * 0.001f * timespeed + daytime_offset_);
} }
game::DrivableVehicle& game::OpenWorld::SpawnRandomVehicle() game::DrivableVehicle& game::OpenWorld::SpawnRandomVehicle()

View File

@ -9,14 +9,19 @@ namespace game
class OpenWorld : public EnterableWorld class OpenWorld : public EnterableWorld
{ {
public: public:
using Super = EnterableWorld;
OpenWorld(); OpenWorld();
virtual void Update(int64_t delta_time) override;
private: private:
game::DrivableVehicle& SpawnRandomVehicle(); game::DrivableVehicle& SpawnRandomVehicle();
void SpawnBot(); void SpawnBot();
private: private:
std::vector<NpcCharacter*> npcs_; std::vector<NpcCharacter*> npcs_;
float daytime_offset_ = 0.0f;
}; };
} }

View File

@ -116,6 +116,7 @@ void game::Player::SyncWorld()
if (world_) if (world_)
{ {
SendWorldUpdateMsg(); SendWorldUpdateMsg();
SendEnv();
SyncEntities(); SyncEntities();
} }
} }
@ -125,6 +126,8 @@ void game::Player::SendWorldMsg()
MSGDEBUG(std::cout << "seding CHWORLD" << std::endl;) MSGDEBUG(std::cout << "seding CHWORLD" << std::endl;)
auto msg = BeginMsg(net::MSG_CHWORLD); auto msg = BeginMsg(net::MSG_CHWORLD);
world_->SendInitData(*this, msg); world_->SendInitData(*this, msg);
last_env_time_ = 0; // reset after world changed
} }
void game::Player::SendWorldUpdateMsg() void game::Player::SendWorldUpdateMsg()
@ -136,6 +139,17 @@ void game::Player::SendWorldUpdateMsg()
msg.Write(world_->GetMsg()); msg.Write(world_->GetMsg());
} }
void game::Player::SendEnv()
{
if (!world_ || last_env_time_ + 1000 > world_->GetTime())
return;
last_env_time_ = world_->GetTime();
auto msg = BeginMsg(net::MSG_ENV);
msg.Write<net::DayTimeQ>(world_->GetDayTime());
}
void game::Player::SyncEntities() void game::Player::SyncEntities()
{ {
// update cull pos // update cull pos

View File

@ -53,6 +53,7 @@ private:
void SyncWorld(); void SyncWorld();
void SendWorldMsg(); void SendWorldMsg();
void SendWorldUpdateMsg(); void SendWorldUpdateMsg();
void SendEnv();
// entities sync // entities sync
void SyncEntities(); void SyncEntities();
@ -78,6 +79,7 @@ private:
World* world_ = nullptr; World* world_ = nullptr;
World* known_world_ = nullptr; World* known_world_ = nullptr;
std::set<net::EntNum> known_ents_; std::set<net::EntNum> known_ents_;
int64_t last_env_time_ = 0;
PlayerInputFlags in_ = 0; PlayerInputFlags in_ = 0;
float view_yaw_ = 0.0f, view_pitch_ = 0.0f; float view_yaw_ = 0.0f, view_pitch_ = 0.0f;

View File

@ -49,6 +49,8 @@ public:
const std::string& GetMapName() const { return map_.GetName(); } const std::string& GetMapName() const { return map_.GetName(); }
const std::map<net::EntNum, std::unique_ptr<Entity>>& GetEntities() const { return ents_; } const std::map<net::EntNum, std::unique_ptr<Entity>>& GetEntities() const { return ents_; }
const int64_t& GetTime() const { return time_ms_; } const int64_t& GetTime() const { return time_ms_; }
float GetDayTime() const { return daytime_; }
void SetDayTime(float daytime) { daytime_ = glm::mod(daytime, 24.0f); }
virtual ~World() = default; virtual ~World() = default;
@ -68,6 +70,7 @@ private:
net::EntNum last_entnum_ = 0; net::EntNum last_entnum_ = 0;
int64_t time_ms_ = 0; int64_t time_ms_ = 0;
float daytime_ = 12.0f;
}; };
} // namespace game } // namespace game

View File

@ -228,7 +228,9 @@ void game::view::ClientSession::DrawWorld(gfx::DrawList& dlist, gfx::DrawListPar
// 0.0f, 1.0f)); // 0.0f, 1.0f));
float aspect = static_cast<float>(params.screen_width) / static_cast<float>(params.screen_height); float aspect = static_cast<float>(params.screen_width) / static_cast<float>(params.screen_height);
glm::mat4 proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, 3000.0f); const float farplane = 3000.0f;
glm::mat4 proj = glm::perspective(glm::radians(45.0f), aspect, 0.1f, farplane);
glm::vec3 eye; glm::vec3 eye;
glm::mat4 view; glm::mat4 view;
GetViewInfo(eye, view); GetViewInfo(eye, view);
@ -239,7 +241,7 @@ void game::view::ClientSession::DrawWorld(gfx::DrawList& dlist, gfx::DrawListPar
// glm::mat4 fake_view_proj = glm::perspective(glm::radians(30.0f), aspect, 0.1f, 3000.0f) * view; // glm::mat4 fake_view_proj = glm::perspective(glm::radians(30.0f), aspect, 0.1f, 3000.0f) * view;
game::view::DrawArgs draw_args(dlist, params.env, gui, params.view_proj, eye, game::view::DrawArgs draw_args(dlist, params.env, gui, params.view_proj, eye,
glm::ivec2(params.screen_width, params.screen_height), 500.0f); glm::ivec2(params.screen_width, params.screen_height), farplane, 500.0f);
world_->Draw(draw_args); world_->Draw(draw_args);
glm::mat4 camera_world = glm::inverse(view); glm::mat4 camera_world = glm::inverse(view);

View File

@ -18,12 +18,13 @@ struct DrawArgs
const glm::vec3 eye; const glm::vec3 eye;
const gfx::Frustum frustum; const gfx::Frustum frustum;
const glm::ivec2 screen_size; const glm::ivec2 screen_size;
const float farplane;
const float render_distance; const float render_distance;
DrawArgs(gfx::DrawList& dlist, gfx::DrawListEnvironmentParams& env, gui::Context& gui, const glm::mat4& view_proj, DrawArgs(gfx::DrawList& dlist, gfx::DrawListEnvironmentParams& env, gui::Context& gui, const glm::mat4& view_proj,
const glm::vec3& eye, const glm::ivec2& screen_size, float render_distance) const glm::vec3& eye, const glm::ivec2& screen_size, float farplane, float render_distance)
: dlist(dlist), env(env), gui(gui), view_proj(view_proj), eye(eye), frustum(view_proj), : dlist(dlist), env(env), gui(gui), view_proj(view_proj), eye(eye), frustum(view_proj),
screen_size(screen_size), render_distance(render_distance) screen_size(screen_size), farplane(farplane), render_distance(render_distance)
{ {
} }
}; };

233
src/gameview/worldenv.cpp Normal file
View File

@ -0,0 +1,233 @@
#include "worldenv.hpp"
#include "assets/cache.hpp"
game::view::WorldEnv::WorldEnv()
{
sunmodel_ = assets::CacheManager::GetModel("data/env_sun.mdl");
moonmodel_ = assets::CacheManager::GetModel("data/env_moon.mdl");
halfspheremodel_ = assets::CacheManager::GetModel("data/env_halfsphere.mdl");
}
static const glm::vec4 color1(1.0f);
static const game::view::WorldEnvKeyframe env_kfs[] = {
game::view::WorldEnvKeyframe{
0.0f, // time
glm::vec3(0.1f, 0.15f, 0.3f), // clear color
glm::vec3(0.4f, 0.4f, 0.4f), // ambient color
glm::vec3(0.5f, 0.8f, 1.0f) * 0.4f, // sun color
-1.0f, // sun light source
glm::vec4(1.0f, 1.0f, 1.0f, 0.0f), // sun disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.0f), // sun halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), // moon disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.1f), // moon halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 10000.0f), // fog
},
game::view::WorldEnvKeyframe{
5.0f, // time
glm::vec3(0.15f, 0.2, 0.3f), // clear color
glm::vec3(0.5f, 0.5f, 0.5f) * 1.0f, // ambient color
glm::vec3(0.5f, 0.8f, 1.0f) * 0.4f, // sun color
-1.0f, // sun light source
glm::vec4(1.0f, 0.9f, 0.8f, 1.0f), // sun disc color
glm::vec4(1.0f, 0.8f, 0.6f, 0.2f), // sun halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), // moon disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.0f), // moon halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 10000.0f), // fog
},
game::view::WorldEnvKeyframe{
6.0f, // time
glm::vec3(0.65f, 0.8f, 1.0f) * 0.9f, // clear color
glm::vec3(0.5f, 0.5f, 0.5f) * 1.1f, // ambient color
glm::vec3(1.0f, 0.95f, 0.7f) * 0.8f, // sun color
1.0f, // sun light source
glm::vec4(1.0f, 0.9f, 0.8f, 1.0f), // sun disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.4f), // sun halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 0.0f), // moon disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.0f), // moon halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 10000.0f), // fog
},
game::view::WorldEnvKeyframe{
12.0f, // time
glm::vec3(0.6f, 0.8f, 1.0f), // clear color
glm::vec3(0.5f, 0.5f, 0.5f) * 0.9f, // ambient color
glm::vec3(1.0f, 0.95f, 0.7f) * 0.9f, // sun color
1.0f, // sun light source
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), // sun disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.7f), // sun halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 0.0f), // moon disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.0f), // moon halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 10000.0f), // fog
},
game::view::WorldEnvKeyframe{
17.0f, // time
glm::vec3(0.5f, 0.7f, 1.0f) * 0.9f, // clear color
glm::vec3(0.5f, 0.5f, 0.5f) * 1.1f, // ambient color
glm::vec3(1.0f, 0.95f, 0.7f) * 0.9f, // sun color
1.0f, // sun light source
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), // sun disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.5f), // sun halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 0.0f), // moon disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.0f), // moon halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 10000.0f), // fog
},
game::view::WorldEnvKeyframe{
17.5f, // time
glm::vec3(0.5f, 0.7f, 1.0f) * 0.8f, // clear color
glm::vec3(0.8f, 0.6f, 0.5f) * 0.8f, // ambient color
glm::vec3(1.0f, 0.8f, 0.6f) * 0.8f, // sun color
1.0f, // sun light source
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), // sun disc color
glm::vec4(1.0f, 0.7f, 0.5f, 1.0f), // sun halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 0.2f), // moon disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.1f), // moon halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 10000.0f), // fog
},
game::view::WorldEnvKeyframe{
18.0f, // time
glm::vec3(0.5f, 0.7f, 1.0f) * 0.7f, // clear color
glm::vec3(0.8f, 0.6f, 0.5f) * 0.8f, // ambient color
glm::vec3(1.0f, 0.8f, 0.6f) * 0.8f, // sun color
0.0f, // sun light source
glm::vec4(1.0f, 0.8f, 0.7f, 1.0f), // sun disc color
glm::vec4(1.0f, 0.7f, 0.5f, 1.0f), // sun halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 0.2f), // moon disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.1f), // moon halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 10000.0f), // fog
},
game::view::WorldEnvKeyframe{
19.0f, // time
glm::vec3(0.1f, 0.15f, 0.3f), // clear color
glm::vec3(0.4f, 0.4f, 0.4f), // ambient color
glm::vec3(0.5f, 0.8f, 1.0f) * 0.4f, // sun color
-1.0f, // sun light source
glm::vec4(1.0f, 0.5f, 0.3f, 1.0f), // sun disc color
glm::vec4(1.0f, 0.5f, 0.2f, 0.8f), // sun halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), // moon disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.1f), // moon halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 10000.0f), // fog
},
game::view::WorldEnvKeyframe{
20.0f, // time
glm::vec3(0.1f, 0.15f, 0.3f), // clear color
glm::vec3(0.4f, 0.4f, 0.4f), // ambient color
glm::vec3(0.5f, 0.8f, 1.0f) * 0.4f, // sun color
-1.0f, // sun light source
glm::vec4(1.0f, 1.0f, 1.0f, 0.0f), // sun disc color
glm::vec4(1.0f, 0.5f, 0.2f, 0.0f), // sun halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), // moon disc color
glm::vec4(1.0f, 1.0f, 1.0f, 0.1f), // moon halfsphere color
glm::vec4(1.0f, 1.0f, 1.0f, 10000.0f), // fog
},
};
void game::view::WorldEnv::Draw(const DrawArgs& args)
{
const WorldEnvKeyframe *kf1, *kf2;
if (daytime_ < 0.0f)
daytime_ = 0.0f;
const size_t num_kfs = sizeof(env_kfs) / sizeof(WorldEnvKeyframe);
for (size_t i = 0; i < num_kfs; ++i)
{
if (daytime_ >= env_kfs[i].daytime)
{
kf1 = &env_kfs[i];
kf2 = &env_kfs[(i + 1) % num_kfs];
}
}
float t2 = kf2->daytime;
if (t2 < daytime_)
t2 += 24.0f;
float t = (daytime_ - kf1->daytime) / (t2 - kf1->daytime);
// args.env.clear_color = glm::vec3(0.1f, 0.15f, 0.3f);
// args.env.ambient_light = glm::vec3(0.4f, 0.4f, 0.4f);
// args.env.sun_color = glm::vec3(0.5f, 0.8f, 1.0f) * 0.4f;
// args.env.sun_direction = glm::normalize(glm::vec3(1.0f, 1.0f, -1.0f));
args.env.clear_color = glm::mix(kf1->clear_color, kf2->clear_color, t);
args.env.ambient_light = glm::mix(kf1->ambient_color, kf2->ambient_color, t);
args.env.sun_color = glm::mix(kf1->sun_color, kf2->sun_color, t);
args.env.fog = glm::mix(kf1->fog, kf2->fog, t);
float dist = args.farplane * 0.5f;
// std::cout<<daytime_<<std::endl;
float sun_angle = (daytime_ - 12.0f) * glm::two_pi<float>() / 24.0f;
sun_color_ = glm::mix(kf1->sun_disc_color, kf2->sun_disc_color, t);
sun_matrix_ = glm::mat4(1.0f);
sun_matrix_ = glm::translate(sun_matrix_, args.eye);
sun_matrix_ = glm::scale(sun_matrix_, glm::vec3(dist));
sun_matrix_ = glm::rotate(sun_matrix_, 0.3f, glm::vec3(1.0f, 0.0f, 0.0f));
sun_matrix_ = glm::rotate(sun_matrix_, sun_angle, glm::vec3(0.0f, 1.0f, 0.0f));
sun_matrix_ = glm::translate(sun_matrix_, glm::vec3(0.0f, 0.0f, 1.0f));
sun_matrix_ = glm::scale(sun_matrix_, glm::vec3(0.7f));
sun_halfsphere_color_ = glm::mix(kf1->sun_halfsphere_color, kf2->sun_halfsphere_color, t);
sun_halfsphere_matrix_ = glm::scale(sun_matrix_, glm::vec3(1.0f, 1.0f, 1.5f));
moon_color_ = glm::mix(kf1->moon_disc_color, kf2->moon_disc_color, t);
moon_matrix_ = glm::mat4(1.0f);
moon_matrix_ = glm::translate(moon_matrix_, args.eye);
moon_matrix_ = glm::scale(moon_matrix_, glm::vec3(dist));
moon_matrix_ = glm::rotate(moon_matrix_, sun_angle + glm::pi<float>(), glm::vec3(0.0f, 1.0f, 0.0f));
moon_matrix_ = glm::translate(moon_matrix_, glm::vec3(0.0f, 0.0f, 1.0f));
moon_matrix_ = glm::scale(moon_matrix_, glm::vec3(0.6f));
moon_halfsphere_color_ = glm::mix(kf1->moon_halfsphere_color, kf2->moon_halfsphere_color, t);
moon_halfsphere_matrix_ = glm::scale(moon_matrix_, glm::vec3(1.1f, 1.1f, 1.5f));
float sun_dir = glm::mix(kf1->sun_dir, kf2->sun_dir, t);
if (sun_dir >= 0.0f)
{
args.env.sun_direction = -glm::normalize(glm::vec3(sun_matrix_[2]));
args.env.sun_color *= sun_dir;
}
else
{
args.env.sun_direction = -glm::normalize(glm::vec3(moon_matrix_[2]));
args.env.sun_color *= -sun_dir;
}
DrawEnvModel(args, *halfspheremodel_, moon_halfsphere_matrix_, moon_halfsphere_color_, dist);
DrawEnvModel(args, *halfspheremodel_, sun_halfsphere_matrix_, sun_halfsphere_color_, dist - 1.0f);
DrawEnvModel(args, *sunmodel_, moon_matrix_, moon_color_, dist - 2.0f);
DrawEnvModel(args, *sunmodel_, sun_matrix_, sun_color_, dist - 3.0f);
}
void game::view::WorldEnv::DrawEnvModel(const DrawArgs& args, const assets::Model& model, const glm::mat4& matrix,
const glm::vec4& color, float dist)
{
const auto& mesh = model.GetMesh();
for (const auto& surface : mesh->surfaces)
{
gfx::DrawSurfaceCmd cmd{};
cmd.surface = &surface;
cmd.matrices = &matrix;
cmd.color = &color;
cmd.dist = dist;
args.dlist.AddSurface(cmd);
}
}

56
src/gameview/worldenv.hpp Normal file
View File

@ -0,0 +1,56 @@
#include "assets/model.hpp"
#include "draw_args.hpp"
namespace game::view
{
struct WorldEnvKeyframe
{
float daytime;
glm::vec3 clear_color;
glm::vec3 ambient_color;
glm::vec3 sun_color;
float sun_dir; // 1=sun 0=none -1=moon
glm::vec4 sun_disc_color;
glm::vec4 sun_halfsphere_color;
glm::vec4 moon_disc_color;
glm::vec4 moon_halfsphere_color;
glm::vec4 fog;
};
class WorldEnv
{
public:
WorldEnv();
void Draw(const DrawArgs& args);
void SetDayTime(float daytime) { daytime_ = glm::mod(daytime, 24.0f); }
float GetDayTime() const { return daytime_; }
private:
void DrawEnvModel(const DrawArgs& args, const assets::Model& model, const glm::mat4& matrix, const glm::vec4& color, float dist);
private:
float daytime_ = 0.0f; // 0 - 24
std::shared_ptr<const assets::Model> sunmodel_;
std::shared_ptr<const assets::Model> moonmodel_;
std::shared_ptr<const assets::Model> halfspheremodel_;
glm::mat4 sun_matrix_;
glm::vec4 sun_color_;
glm::mat4 moon_matrix_;
glm::vec4 moon_color_;
glm::mat4 sun_halfsphere_matrix_;
glm::vec4 sun_halfsphere_color_;
glm::mat4 moon_halfsphere_matrix_;
glm::vec4 moon_halfsphere_color_;
};
}

View File

@ -38,12 +38,18 @@ game::view::WorldView::WorldView(ClientSession& session, net::InMessage& msg) :
Cache(assets::CacheManager::GetSound("data/breakwood.snd")); Cache(assets::CacheManager::GetSound("data/breakwood.snd"));
Cache(assets::CacheManager::GetSound("data/cardoor.snd")); Cache(assets::CacheManager::GetSound("data/cardoor.snd"));
Cache(assets::CacheManager::GetSound("data/crash.snd")); Cache(assets::CacheManager::GetSound("data/crash.snd"));
env_ = std::make_unique<WorldEnv>();
env_->SetDayTime(12.0f);
} }
bool game::view::WorldView::ProcessMsg(net::MessageType type, net::InMessage& msg) bool game::view::WorldView::ProcessMsg(net::MessageType type, net::InMessage& msg)
{ {
switch (type) switch (type)
{ {
case net::MSG_ENV:
return ProcessEnvMsg(msg);
case net::MSG_ENTSPAWN: case net::MSG_ENTSPAWN:
return ProcessEntSpawnMsg(msg); return ProcessEntSpawnMsg(msg);
@ -78,6 +84,8 @@ void game::view::WorldView::Update(const UpdateInfo& info)
{ {
ent->TryUpdate(info); ent->TryUpdate(info);
} }
UpdateEnv();
} }
void game::view::WorldView::Draw(const DrawArgs& args) const void game::view::WorldView::Draw(const DrawArgs& args) const
@ -88,7 +96,7 @@ void game::view::WorldView::Draw(const DrawArgs& args) const
return; return;
} }
args.env.clear_color = glm::vec3(0.5f, 0.7f, 1.0f); DrawEnv(args);
map_->Draw(args); map_->Draw(args);
@ -149,6 +157,53 @@ void game::view::WorldView::DrawLoadingScreen(const DrawArgs& args) const
args.gui.DrawTextAligned(load_text, pos + glm::vec2(size.x + 50.0f, size.y * 0.5f), glm::vec2(-0.5f, -0.5f)); args.gui.DrawTextAligned(load_text, pos + glm::vec2(size.x + 50.0f, size.y * 0.5f), glm::vec2(-0.5f, -0.5f));
} }
void game::view::WorldView::UpdateEnv()
{
if (!env_)
return;
env_->SetDayTime(glm::mix(daytime0_, daytime1_, glm::clamp(GetTime() - env_msg_time_, 0.0f, 1.0f)));
}
void game::view::WorldView::DrawEnv(const DrawArgs& args) const
{
if (env_)
{
env_->Draw(args);
return;
}
// args.env.clear_color = glm::vec3(0.5f, 0.7f, 1.0f);
args.env.clear_color = glm::vec3(0.1f, 0.15f, 0.3f);
args.env.ambient_light = glm::vec3(0.4f, 0.4f, 0.4f);
args.env.sun_color = glm::vec3(0.5f, 0.8f, 1.0f) * 0.4f;
args.env.sun_direction = glm::normalize(glm::vec3(1.0f, 1.0f, -1.0f));
}
bool game::view::WorldView::ProcessEnvMsg(net::InMessage& msg)
{
float new_daytime;
if (!msg.Read<net::DayTimeQ>(new_daytime))
return false;
if (!env_)
return true;
env_msg_time_ = GetTime();
daytime0_ = env_->GetDayTime();
daytime1_ = new_daytime;
if (daytime1_ < daytime0_)
daytime0_ -= 24.0f;
return true;
}
bool game::view::WorldView::ProcessEntSpawnMsg(net::InMessage& msg) bool game::view::WorldView::ProcessEntSpawnMsg(net::InMessage& msg)
{ {
net::EntNum entnum; net::EntNum entnum;

View File

@ -9,6 +9,7 @@
#include "collision/dynamicsworld.hpp" #include "collision/dynamicsworld.hpp"
#include "entityview.hpp" #include "entityview.hpp"
#include "mapinstanceview.hpp" #include "mapinstanceview.hpp"
#include "worldenv.hpp"
namespace game::view namespace game::view
{ {
@ -35,7 +36,11 @@ public:
private: private:
void DrawLoadingScreen(const DrawArgs& args) const; void DrawLoadingScreen(const DrawArgs& args) const;
void UpdateEnv();
void DrawEnv(const DrawArgs& args) const;
// msg handlers // msg handlers
bool ProcessEnvMsg(net::InMessage& msg);
bool ProcessEntSpawnMsg(net::InMessage& msg); bool ProcessEntSpawnMsg(net::InMessage& msg);
bool ProcessEntMsgMsg(net::InMessage& msg); bool ProcessEntMsgMsg(net::InMessage& msg);
bool ProcessUpdateEntsMsg(net::InMessage& msg); bool ProcessUpdateEntsMsg(net::InMessage& msg);
@ -50,9 +55,14 @@ private:
std::unique_ptr<MapInstanceView> map_; std::unique_ptr<MapInstanceView> map_;
std::map<net::EntNum, std::unique_ptr<EntityView>> ents_; std::map<net::EntNum, std::unique_ptr<EntityView>> ents_;
std::unique_ptr<WorldEnv> env_;
float time_ = 0.0f; float time_ = 0.0f;
float daytime0_ = 0.0f;
float daytime1_ = 0.0f;
float env_msg_time_ = 0.0f;
audio::Master& audiomaster_; audio::Master& audiomaster_;
std::vector<std::any> cache_; std::vector<std::any> cache_;

View File

@ -117,6 +117,12 @@ void gfx::Renderer::SetupMeshShader(MeshShader& mshader, const DrawListParams& p
glUniformMatrix4fv(shader.U(gfx::SU_VIEW_PROJ), 1, GL_FALSE, &params.view_proj[0][0]); glUniformMatrix4fv(shader.U(gfx::SU_VIEW_PROJ), 1, GL_FALSE, &params.view_proj[0][0]);
// setup lighting
glUniform3fv(shader.U(gfx::SU_AMBIENT_LIGHT), 1, &params.env.ambient_light[0]);
glUniform3fv(shader.U(gfx::SU_SUN_COLOR), 1, &params.env.sun_color[0]);
glUniform3fv(shader.U(gfx::SU_SUN_DIRECTION), 1, &params.env.sun_direction[0]);
glUniform4fv(shader.U(gfx::SU_FOG), 1, &params.env.fog[0]);
mshader.global_setup = true; mshader.global_setup = true;
} }
@ -188,7 +194,9 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
const bool twosided_flag = surface->sflags & SF_2SIDED; const bool twosided_flag = surface->sflags & SF_2SIDED;
const bool blend_flag = surface->sflags & SF_BLEND; const bool blend_flag = surface->sflags & SF_BLEND;
const bool object_color_flag = surface->sflags & SF_OBJECT_COLOR; const bool object_color_flag = surface->sflags & SF_OBJECT_COLOR;
const bool object_color_mult_flag = surface->sflags & SF_OBJECT_COLOR_MULT;
const bool deform_flag = surface->sflags & SF_DEFORM_GRID; const bool deform_flag = surface->sflags & SF_DEFORM_GRID;
const bool unlit_flag = surface->sflags & SF_UNLIT;
// sync 2sided // sync 2sided
if (last_twosided != twosided_flag) if (last_twosided != twosided_flag)
@ -223,11 +231,20 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
if (object_color_flag && cmd.color) if (object_color_flag && cmd.color)
{ {
// use object color and disable alpha cull // use object color and disable alpha cull
shflags &= ~SHF_CULL_ALPHA;
shflags |= SHF_BACKGROUND; if (!object_color_mult_flag)
{
shflags &= ~SHF_CULL_ALPHA;
shflags |= SHF_BACKGROUND;
}
color = glm::vec4(*cmd.color); color = glm::vec4(*cmd.color);
} }
// check unlit
if (unlit_flag)
shflags |= SHF_UNLIT;
// sync blending // sync blending
if (blend_flag != last_blend) if (blend_flag != last_blend)
{ {

View File

@ -11,7 +11,11 @@ namespace gfx
struct DrawListEnvironmentParams struct DrawListEnvironmentParams
{ {
glm::vec3 clear_color; glm::vec3 clear_color;
glm::vec3 ambient_light;
glm::vec3 sun_color;
glm::vec3 sun_direction;
glm::vec4 fog; // alpha = distance
}; };
struct DrawListParams struct DrawListParams

View File

@ -13,6 +13,10 @@ static const char* const s_uni_names[] = {
"u_camera", // SU_CAMERA "u_camera", // SU_CAMERA
"u_deform_tex", // SU_DEFORM_TEX "u_deform_tex", // SU_DEFORM_TEX
"u_deform_info", // SU_DEFORM_INFO "u_deform_info", // SU_DEFORM_INFO
"u_ambient_light", // SU_AMBIENT_LIGHT
"u_sun_color", // SU_SUN_COLOR
"u_sun_direction", // SU_SUN_DIRECTION
"u_fog", // SU_FOG
}; };
// Vytvori shader z daneho zdroje // Vytvori shader z daneho zdroje

View File

@ -18,6 +18,10 @@ namespace gfx
SU_CAMERA, SU_CAMERA,
SU_DEFORM_TEX, SU_DEFORM_TEX,
SU_DEFORM_INFO, SU_DEFORM_INFO,
SU_AMBIENT_LIGHT,
SU_SUN_COLOR,
SU_SUN_DIRECTION,
SU_FOG,
SU_COUNT SU_COUNT
}; };

View File

@ -4,4 +4,5 @@
#define SD_MAX_BONES 128 #define SD_MAX_BONES 128
#define SHF_CULL_ALPHA 1 #define SHF_CULL_ALPHA 1
#define SHF_BACKGROUND 2 #define SHF_BACKGROUND 2
#define SHF_UNLIT 4

View File

@ -19,6 +19,9 @@
#define SHADER_DEFS \ #define SHADER_DEFS \
"#define MAX_LIGHTS " STRINGIFY(SD_MAX_LIGHTS) "\n" \ "#define MAX_LIGHTS " STRINGIFY(SD_MAX_LIGHTS) "\n" \
"#define MAX_BONES " STRINGIFY(SD_MAX_BONES) "\n" \ "#define MAX_BONES " STRINGIFY(SD_MAX_BONES) "\n" \
"#define SHF_CULL_ALPHA " STRINGIFY(SHF_CULL_ALPHA) "\n" \
"#define SHF_BACKGROUND " STRINGIFY(SHF_BACKGROUND) "\n" \
"#define SHF_UNLIT " STRINGIFY(SHF_UNLIT) "\n" \
"\n" "\n"
#define SHADER_HEADER \ #define SHADER_HEADER \
@ -32,6 +35,12 @@
#define LIGHT_MATRICES_GLSL R"GLSL( #define LIGHT_MATRICES_GLSL R"GLSL(
uniform vec3 u_ambient_light; uniform vec3 u_ambient_light;
uniform vec3 u_sun_direction;
uniform vec3 u_sun_color;
uniform vec4 u_fog;
uniform int u_flags;
uniform int u_num_lights; uniform int u_num_lights;
uniform vec3 u_light_positions[MAX_LIGHTS]; uniform vec3 u_light_positions[MAX_LIGHTS];
uniform vec4 u_light_colors_rs[MAX_LIGHTS]; // rgb = color, a = radius uniform vec4 u_light_colors_rs[MAX_LIGHTS]; // rgb = color, a = radius
@ -39,13 +48,18 @@
#define COMPUTE_LIGHTS_GLSL R"GLSL( #define COMPUTE_LIGHTS_GLSL R"GLSL(
// Example sun values (can later be uniforms) // Example sun values (can later be uniforms)
vec3 u_sun_direction = normalize(vec3(0.3, 0.5, -0.8)); // direction from which sunlight comes //vec3 u_sun_direction = normalize(vec3(0.3, 0.5, -0.8)); // direction from which sunlight comes
vec3 u_sun_color = vec3(1.0, 0.95, 0.7) * 0.9; // warm sunlight color //vec3 u_sun_color = vec3(1.0, 0.95, 0.7) * 0.9; // warm sunlight color
//uniform vec3 u_ambient_light;
vec3 ComputeLights(in vec3 sector_pos, in vec3 sector_normal) vec3 ComputeLights(in vec3 sector_pos, in vec3 sector_normal)
{ {
if ((u_flags & SHF_UNLIT) > 0)
return vec3(1.0);
// Base ambient // Base ambient
vec3 color = vec3(0.5, 0.5, 0.5) * 0.9; // u_ambient_light vec3 color = u_ambient_light; //vec3(0.5, 0.5, 0.5) * 0.9; // u_ambient_light
// Sunlight contribution // Sunlight contribution
float sun_dot = max(dot(sector_normal, -u_sun_direction), 0.0); float sun_dot = max(dot(sector_normal, -u_sun_direction), 0.0);
@ -107,9 +121,6 @@ R"GLSL(
in vec2 v_uv; in vec2 v_uv;
in vec3 v_color; in vec3 v_color;
#define SHF_CULL_ALPHA 1
#define SHF_BACKGROUND 2
uniform sampler2D u_tex; uniform sampler2D u_tex;
uniform vec4 u_color; uniform vec4 u_color;
uniform int u_flags; uniform int u_flags;
@ -119,16 +130,20 @@ layout (location = 0) out vec4 o_color;
void main() { void main() {
o_color = vec4(texture(u_tex, v_uv)); o_color = vec4(texture(u_tex, v_uv));
if ((u_flags & SHF_BACKGROUND) > 0)
{
o_color = mix(u_color, o_color, o_color.a);
}
else
{
o_color *= u_color;
}
if ((u_flags & SHF_CULL_ALPHA) > 0) if ((u_flags & SHF_CULL_ALPHA) > 0)
{ {
if (o_color.a < 0.5) if (o_color.a < 0.5)
discard; discard;
} }
else if ((u_flags & SHF_BACKGROUND) > 0)
{
// blend with bg
o_color = mix(u_color, o_color, o_color.a);
}
o_color.rgb *= v_color; // Apply vertex color o_color.rgb *= v_color; // Apply vertex color
//o_color = vec4(1.0, 0.0, 0.0, 1.0); //o_color = vec4(1.0, 0.0, 0.0, 1.0);
@ -183,9 +198,6 @@ R"GLSL(
in vec2 v_uv; in vec2 v_uv;
in vec3 v_color; in vec3 v_color;
#define SHF_CULL_ALPHA 1
#define SHF_BACKGROUND 2
uniform sampler2D u_tex; uniform sampler2D u_tex;
uniform vec4 u_color; uniform vec4 u_color;
uniform int u_flags; uniform int u_flags;
@ -195,16 +207,20 @@ layout (location = 0) out vec4 o_color;
void main() { void main() {
o_color = vec4(texture(u_tex, v_uv)); o_color = vec4(texture(u_tex, v_uv));
if ((u_flags & SHF_BACKGROUND) > 0)
{
o_color = mix(u_color, o_color, o_color.a);
}
else
{
o_color *= u_color;
}
if ((u_flags & SHF_CULL_ALPHA) > 0) if ((u_flags & SHF_CULL_ALPHA) > 0)
{ {
if (o_color.a < 0.5) if (o_color.a < 0.5)
discard; discard;
} }
else if ((u_flags & SHF_BACKGROUND) > 0)
{
// blend with bg
o_color = mix(u_color, o_color, o_color.a);
}
o_color.rgb *= v_color; // Apply vertex color o_color.rgb *= v_color; // Apply vertex color
//o_color = vec4(1.0, 0.0, 0.0, 1.0); //o_color = vec4(1.0, 0.0, 0.0, 1.0);
@ -253,9 +269,6 @@ R"GLSL(
in vec2 v_uv; in vec2 v_uv;
in vec3 v_color; in vec3 v_color;
#define SHF_CULL_ALPHA 1
#define SHF_BACKGROUND 2
uniform sampler2D u_tex; uniform sampler2D u_tex;
uniform vec4 u_color; uniform vec4 u_color;
uniform int u_flags; uniform int u_flags;
@ -265,16 +278,20 @@ layout (location = 0) out vec4 o_color;
void main() { void main() {
o_color = vec4(texture(u_tex, v_uv)); o_color = vec4(texture(u_tex, v_uv));
if ((u_flags & SHF_BACKGROUND) > 0)
{
o_color = mix(u_color, o_color, o_color.a);
}
else
{
o_color *= u_color;
}
if ((u_flags & SHF_CULL_ALPHA) > 0) if ((u_flags & SHF_CULL_ALPHA) > 0)
{ {
if (o_color.a < 0.5) if (o_color.a < 0.5)
discard; discard;
} }
else if ((u_flags & SHF_BACKGROUND) > 0)
{
// blend with bg
o_color = mix(u_color, o_color, o_color.a);
}
o_color.rgb *= v_color; // Apply vertex color o_color.rgb *= v_color; // Apply vertex color
//o_color = vec4(1.0, 0.0, 0.0, 1.0); //o_color = vec4(1.0, 0.0, 0.0, 1.0);

View File

@ -26,6 +26,8 @@ enum SurfaceFlag : SurfaceFlags
SF_BLEND_ADDITIVE = 0x04, // use additive blending instead of opacity SF_BLEND_ADDITIVE = 0x04, // use additive blending instead of opacity
SF_OBJECT_COLOR = 0x08, // use object color for background instead of alpha culling SF_OBJECT_COLOR = 0x08, // use object color for background instead of alpha culling
SF_DEFORM_GRID = 0x10, // use deform grid SF_DEFORM_GRID = 0x10, // use deform grid
SF_UNLIT = 0x20, // dont apply lighting
SF_OBJECT_COLOR_MULT = 0x40, // object color multiplies instead of acting as background
}; };
struct Surface struct Surface

View File

@ -34,6 +34,9 @@ enum MessageType : uint8_t
// CHWORLD <MapName> // CHWORLD <MapName>
MSG_CHWORLD, MSG_CHWORLD,
// ENV <DayTimeQ>
MSG_ENV,
// CAM <EntNum> // CAM <EntNum>
MSG_CAM, MSG_CAM,
@ -76,6 +79,9 @@ constexpr long long PI_D = 78256779;
using ViewYawQ = Quantized<uint16_t, 0, 2 * PI_N, PI_D>; using ViewYawQ = Quantized<uint16_t, 0, 2 * PI_N, PI_D>;
using ViewPitchQ = Quantized<uint16_t, -PI_N, PI_N, PI_D>; using ViewPitchQ = Quantized<uint16_t, -PI_N, PI_N, PI_D>;
// env
using DayTimeQ = Quantized<uint16_t, 0, 24>;
// entities // entities
using EntNum = uint16_t; using EntNum = uint16_t;
using EntCount = EntNum; using EntCount = EntNum;
@ -182,5 +188,4 @@ enum MenuActionType
using MenuSelectDir = uint8_t; // 0=left, 1=right using MenuSelectDir = uint8_t; // 0=left, 1=right
} // namespace net } // namespace net

View File

@ -1,3 +1,3 @@
#pragma once #pragma once
#define FEKAL_VERSION 2026050901 #define FEKAL_VERSION 2026051901