Lights & vehicle lights
This commit is contained in:
parent
0b3b1d09ab
commit
7ea00e2ed4
@ -112,6 +112,10 @@ 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_MULT;)
|
||||
}
|
||||
else if (flag == "+multicolor")
|
||||
{
|
||||
CLIENT_ONLY(sflags |= gfx::SF_MULTICOLOR;)
|
||||
}
|
||||
else if (flag == "+blend")
|
||||
{
|
||||
std::string blend_str;
|
||||
|
||||
@ -61,11 +61,21 @@ bool game::DrivableVehicle::SetPassenger(uint32_t seat_idx, ControllableCharacte
|
||||
|
||||
seat_info.occupant = character;
|
||||
|
||||
if (seat_idx == 0 && !character)
|
||||
if (seat_idx == 0)
|
||||
{
|
||||
// clear inputs
|
||||
SetInputs(0);
|
||||
SetSteering(false, 0.0f);
|
||||
if (character)
|
||||
{
|
||||
SetLightsOn(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetLightsOn(false);
|
||||
|
||||
// clear inputs
|
||||
SetInputs(0);
|
||||
SetSteering(false, 0.0f);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
@ -44,6 +44,7 @@ void game::Vehicle::Update()
|
||||
UpdateCrash();
|
||||
ProcessInput();
|
||||
UpdateWheels();
|
||||
UpdateLights();
|
||||
|
||||
sync_current_ = 1 - sync_current_;
|
||||
UpdateSyncState();
|
||||
@ -177,23 +178,38 @@ void game::Vehicle::ProcessInput()
|
||||
const bool in_left = in_ & (1 << VIN_LEFT);
|
||||
const bool in_right = in_ & (1 << VIN_RIGHT);
|
||||
|
||||
bool active_braking = false;
|
||||
bool active_gas = false;
|
||||
|
||||
if (in_forward)
|
||||
{
|
||||
if (speed < -1)
|
||||
{
|
||||
breakingForce = maxBreakingForce;
|
||||
active_braking = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
engineForce = maxEngineForce;
|
||||
active_gas = true;
|
||||
}
|
||||
}
|
||||
if (in_backward)
|
||||
{
|
||||
if (speed > 1)
|
||||
{
|
||||
breakingForce = maxBreakingForce;
|
||||
active_braking = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
engineForce = -maxEngineForce / 2;
|
||||
active_gas = true;
|
||||
}
|
||||
}
|
||||
|
||||
// idle breaking
|
||||
if (!in_forward && !in_backward)
|
||||
if (!active_braking && !active_gas)
|
||||
{
|
||||
breakingForce = 20.0f;
|
||||
}
|
||||
@ -272,11 +288,14 @@ void game::Vehicle::ProcessInput()
|
||||
}
|
||||
}
|
||||
|
||||
if (glm::abs(engineForce) > 0)
|
||||
if (active_gas)
|
||||
flags_ |= VF_ACCELERATING;
|
||||
|
||||
if (glm::abs(breakingForce) > 0)
|
||||
flags_ |= VF_BREAKING;
|
||||
if (active_braking)
|
||||
flags_ |= VF_BRAKING;
|
||||
|
||||
if (active_gas && engineForce < 0.0f)
|
||||
flags_ |= VF_REVERSING;
|
||||
|
||||
const bool can_roll = wheels_on_ground_ <= (wheels_.size() / 2);
|
||||
|
||||
@ -380,6 +399,14 @@ void game::Vehicle::UpdateWheels()
|
||||
}
|
||||
}
|
||||
|
||||
void game::Vehicle::UpdateLights()
|
||||
{
|
||||
if (lights_on_)
|
||||
flags_ |= VF_LIGHTS_ON;
|
||||
|
||||
// TODO: orange lights
|
||||
}
|
||||
|
||||
void game::Vehicle::UpdateSyncState()
|
||||
{
|
||||
VehicleSyncState& state = sync_[sync_current_];
|
||||
|
||||
@ -74,6 +74,9 @@ public:
|
||||
|
||||
void SetSteering(bool analog, float value = 0.0f);
|
||||
|
||||
void SetLightsOn(bool lights_on) { lights_on_ = lights_on; }
|
||||
bool GetLightsOn() const { return lights_on_; }
|
||||
|
||||
virtual void SetTuning(const VehicleTuning& tuning);
|
||||
|
||||
const std::string& GetModelName() const { return tuning_.model; }
|
||||
@ -87,6 +90,7 @@ private:
|
||||
void ProcessInput();
|
||||
void UpdateCrash();
|
||||
void UpdateWheels();
|
||||
void UpdateLights();
|
||||
void UpdateSyncState();
|
||||
|
||||
VehicleSyncFieldFlags WriteState(net::OutMessage& msg, const VehicleSyncState& base) const;
|
||||
@ -135,6 +139,8 @@ private:
|
||||
size_t wheels_on_ground_ = 0;
|
||||
size_t can_roll_frames_ = 0;
|
||||
|
||||
bool lights_on_ = false;
|
||||
|
||||
};
|
||||
|
||||
} // namespace game
|
||||
@ -13,10 +13,13 @@ using VehicleFlags = uint8_t;
|
||||
|
||||
enum VehicleFlag : VehicleFlags
|
||||
{
|
||||
VF_NONE,
|
||||
VF_ACCELERATING = 0x01,
|
||||
VF_BREAKING = 0x02,
|
||||
VF_BROKENWINDOWS = 0x04,
|
||||
VF_NONE = 0,
|
||||
VF_ACCELERATING = 1,
|
||||
VF_BRAKING = 2,
|
||||
VF_BROKENWINDOWS = 4,
|
||||
VF_LIGHTS_ON = 8,
|
||||
VF_REVERSING = 16,
|
||||
VF_ORANGE_LIGHTS_ON = 32,
|
||||
};
|
||||
|
||||
struct VehicleSyncState
|
||||
|
||||
@ -4,6 +4,7 @@
|
||||
#include "net/utils.hpp"
|
||||
#include "worldview.hpp"
|
||||
#include "utils/random.hpp"
|
||||
#include "utils/math.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <ranges>
|
||||
@ -18,6 +19,7 @@ game::view::VehicleView::VehicleView(WorldView& world, net::InMessage& msg)
|
||||
model_ = assets::CacheManager::GetVehicleModel("data/" + std::string(modelname) + ".veh");
|
||||
mesh_ = *model_->GetModel()->GetMesh();
|
||||
InitMesh();
|
||||
InitHeadlights();
|
||||
|
||||
auto& modelwheels = model_->GetWheels();
|
||||
wheels_.resize(modelwheels.size());
|
||||
@ -117,6 +119,8 @@ void game::view::VehicleView::Update(const UpdateInfo& info)
|
||||
mesh_.surfaces[idx].texture = assets::CacheManager::GetTexture("data/carbrokenwindows.png");
|
||||
}
|
||||
}
|
||||
|
||||
UpdateLights(info.delta_time);
|
||||
}
|
||||
|
||||
void game::view::VehicleView::Draw(const DrawArgs& args)
|
||||
@ -129,6 +133,7 @@ void game::view::VehicleView::Draw(const DrawArgs& args)
|
||||
cmd.surface = &surface;
|
||||
cmd.matrices = &root_.matrix;
|
||||
cmd.color = &colors_[0];
|
||||
cmd.num_colors = SD_MAX_COLORS;
|
||||
args.dlist.AddSurface(cmd);
|
||||
}
|
||||
|
||||
@ -157,6 +162,29 @@ void game::view::VehicleView::Draw(const DrawArgs& args)
|
||||
args.dlist.AddBeam(start, end, 0xFFFFFF00, 0.01f);
|
||||
args.dlist.AddBeam(end, end2, 0xFFFF00FF, 0.01f);
|
||||
}
|
||||
|
||||
// headlights
|
||||
if (headlights_factor_ >= 0.01f)
|
||||
{
|
||||
// light
|
||||
auto light_pos = world_.CameraSweep(root_.GetGlobalPosition(), root_.matrix * glm::vec4(0.0f, 7.0f, 0.0f, 1.0f));
|
||||
args.dlist.AddLight(light_pos, glm::vec3(1.0f, 1.0f, 1.0f) * headlights_factor_, 5.0f);
|
||||
|
||||
// cones
|
||||
for (size_t i = 0; i < num_headlights; ++i)
|
||||
{
|
||||
auto& cone_surfaces = light_cone_mdl_->GetMesh()->surfaces;
|
||||
|
||||
for (const auto& surface : cone_surfaces)
|
||||
{
|
||||
gfx::DrawSurfaceCmd cmd;
|
||||
cmd.surface = &surface;
|
||||
cmd.matrices = &light_cone_node_[i].matrix;
|
||||
cmd.color = &headlight_cone_color_;
|
||||
args.dlist.AddSurface(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void game::view::VehicleView::InitMesh()
|
||||
@ -188,6 +216,8 @@ void game::view::VehicleView::InitMesh()
|
||||
|
||||
bool game::view::VehicleView::ReadTuning(net::InMessage& msg)
|
||||
{
|
||||
glm::vec4 recv_colors[4];
|
||||
|
||||
// read colors
|
||||
for (size_t i = 0; i < 4; ++i)
|
||||
{
|
||||
@ -196,7 +226,7 @@ bool game::view::VehicleView::ReadTuning(net::InMessage& msg)
|
||||
if (!net::ReadRGB(msg, color))
|
||||
return false;
|
||||
|
||||
colors_[i] = glm::unpackUnorm4x8(color);
|
||||
recv_colors[i] = glm::unpackUnorm4x8(color);
|
||||
}
|
||||
|
||||
// read wheel models
|
||||
@ -210,9 +240,12 @@ bool game::view::VehicleView::ReadTuning(net::InMessage& msg)
|
||||
std::string wheel_model_name = wheelmodel_fixed;
|
||||
|
||||
wheels_[i].model = !wheel_model_name.empty() ? assets::CacheManager::GetModel("data/" + wheel_model_name + ".mdl") : model_->GetWheels()[i].model;
|
||||
wheels_[i].color = colors_[1]; // TODO: dynamic?;
|
||||
wheels_[i].color = recv_colors[1]; // TODO: dynamic?;
|
||||
}
|
||||
|
||||
colors_[VCS_PRIMARY] = recv_colors[0]; // primary
|
||||
colors_[VCS_SECONDARY] = recv_colors[0]; // secondary
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -346,3 +379,52 @@ bool game::view::VehicleView::ProcessDeformMsg(net::InMessage& msg)
|
||||
|
||||
|
||||
}
|
||||
|
||||
void game::view::VehicleView::InitHeadlights()
|
||||
{
|
||||
for (size_t i = 0; i < 2; ++i)
|
||||
{
|
||||
std::string loc_name = std::string("headlight") + static_cast<char>('0' + i);
|
||||
auto loc = model_->GetLocation(loc_name);
|
||||
|
||||
if (!loc)
|
||||
break;
|
||||
|
||||
if (!light_cone_mdl_)
|
||||
{
|
||||
light_cone_mdl_ = assets::CacheManager::GetModel("data/headlightcone.mdl");
|
||||
}
|
||||
|
||||
light_cone_node_[i].parent = &root_;
|
||||
light_cone_node_[i].local.position = loc->position;
|
||||
|
||||
++num_headlights;
|
||||
}
|
||||
}
|
||||
|
||||
void game::view::VehicleView::UpdateLights(float delta_t)
|
||||
{
|
||||
float max_delta = delta_t * 10.0f;
|
||||
|
||||
MoveToward(headlights_factor_, (flags_ & VF_LIGHTS_ON) ? 1.0f : 0.0f, max_delta);
|
||||
MoveToward(braking_lights_factor_, (flags_ & VF_BRAKING) ? 1.0f : 0.0f, max_delta);
|
||||
MoveToward(orange_lights_factor_, (flags_ & VF_ORANGE_LIGHTS_ON) ? 1.0f : 0.0f, max_delta);
|
||||
MoveToward(reverse_light_factor_, (flags_ & VF_REVERSING) ? 1.0f : 0.0f, max_delta);
|
||||
|
||||
colors_[VCS_HEADLIGHTS] = glm::vec4(1.0f, 1.0f, 1.0f, headlights_factor_);
|
||||
colors_[VCS_REAR_LIGHTS] = glm::vec4(1.0f, 1.0f, 1.0f, headlights_factor_ * 0.5f + braking_lights_factor_ * 1.0f);
|
||||
colors_[VCS_BRAKING_LIGHTS] = glm::vec4(1.0f, 1.0f, 1.0f, braking_lights_factor_);
|
||||
colors_[VCS_ORANGE_LIGHTS] = glm::vec4(1.0f, 1.0f, 1.0f, orange_lights_factor_);
|
||||
colors_[VCS_REVERSE_LIGHT] = glm::vec4(1.0f, 1.0f, 1.0f, reverse_light_factor_);
|
||||
|
||||
if (headlights_factor_ < 0.01f)
|
||||
return;
|
||||
|
||||
float intensity = headlights_factor_ * 0.2f;
|
||||
headlight_cone_color_ = glm::vec4(intensity, intensity, intensity, 1.0f);
|
||||
|
||||
for (size_t i = 0; i < num_headlights; ++i)
|
||||
{
|
||||
light_cone_node_[i].UpdateMatrix();
|
||||
}
|
||||
}
|
||||
|
||||
@ -31,6 +31,20 @@ struct VehicleDeformView
|
||||
VehicleDeformView(const gfx::DeformGridInfo& info) : grid(info), tex(std::make_shared<gfx::DeformTexture>(info)) {}
|
||||
};
|
||||
|
||||
enum VehicleColorSlot
|
||||
{
|
||||
VCS_PRIMARY,
|
||||
VCS_SECONDARY,
|
||||
|
||||
VCS_HEADLIGHTS,
|
||||
VCS_REAR_LIGHTS,
|
||||
VCS_BRAKING_LIGHTS,
|
||||
VCS_ORANGE_LIGHTS,
|
||||
VCS_REVERSE_LIGHT,
|
||||
|
||||
VCS_RESERVED,
|
||||
};
|
||||
|
||||
class VehicleView : public EntityView
|
||||
{
|
||||
using Super = EntityView;
|
||||
@ -52,10 +66,14 @@ private:
|
||||
bool ReadDeformSync(net::InMessage& msg);
|
||||
bool ProcessDeformMsg(net::InMessage& msg);
|
||||
|
||||
void InitHeadlights();
|
||||
|
||||
void UpdateLights(float delta_t);
|
||||
|
||||
private:
|
||||
std::shared_ptr<const assets::VehicleModel> model_;
|
||||
assets::Mesh mesh_;
|
||||
glm::vec4 colors_[4];
|
||||
glm::vec4 colors_[SD_MAX_COLORS];
|
||||
|
||||
game::VehicleSyncState sync_;
|
||||
std::vector<VehicleWheelViewInfo> wheels_;
|
||||
@ -71,6 +89,18 @@ private:
|
||||
bool windows_broken_ = false;
|
||||
std::unique_ptr<VehicleDeformView> deform_;
|
||||
std::vector<std::tuple<glm::vec3, glm::vec3>> debug_deforms_;
|
||||
|
||||
// lights
|
||||
float headlights_factor_ = 0.0f;
|
||||
float braking_lights_factor_ = 0.0f;
|
||||
float orange_lights_factor_ = 0.0f;
|
||||
float reverse_light_factor_ = 0.0f;
|
||||
|
||||
size_t num_headlights = 0;
|
||||
std::shared_ptr<const assets::Model> light_cone_mdl_;
|
||||
TransformNode light_cone_node_[2];
|
||||
glm::vec4 headlight_cone_color_;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@ -3,9 +3,10 @@
|
||||
#include <vector>
|
||||
|
||||
#include "assets/skeleton.hpp"
|
||||
#include "light_cache.hpp"
|
||||
#include "surface.hpp"
|
||||
#include "uniform_buffer.hpp"
|
||||
#include "surface_render_flags.hpp"
|
||||
#include "uniform_buffer.hpp"
|
||||
|
||||
namespace gfx
|
||||
{
|
||||
@ -13,13 +14,26 @@ namespace gfx
|
||||
struct DrawSurfaceCmd
|
||||
{
|
||||
const Surface* surface = nullptr;
|
||||
const glm::mat4* matrices = nullptr; // model matrix
|
||||
const glm::vec4* color = nullptr; // optional tint
|
||||
uint32_t first = 0; // first triangle index
|
||||
uint32_t count = 0; // num triangles
|
||||
float dist = 0.0f; // distance to camera - for transparnt sorting
|
||||
const glm::mat4* matrices = nullptr; // model matrix
|
||||
const glm::vec4* color = nullptr; // optional tint
|
||||
const UniformBuffer<glm::mat4>* skinning = nullptr; // skinning matrices for skeletal meshes
|
||||
uint32_t first = 0; // first triangle index
|
||||
uint32_t count = 0; // num triangles
|
||||
float dist = 0.0f; // distance to camera - for transparnt sorting
|
||||
SurfaceRenderFlags rflags = 0;
|
||||
uint8_t num_colors = 0; // >0 for multicolor, requires array of colors in "color"
|
||||
};
|
||||
|
||||
struct DrawLightCmd
|
||||
{
|
||||
glm::vec3 position = glm::vec3(0.0f);
|
||||
glm::vec3 color = glm::vec3(1.0f);
|
||||
float radius = 1.0f;
|
||||
|
||||
DrawLightCmd(const glm::vec3& position, const glm::vec3& color, float radius)
|
||||
: position(position), color(color), radius(radius)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
struct DrawBeamCmd
|
||||
@ -31,8 +45,8 @@ struct DrawBeamCmd
|
||||
size_t num_segments;
|
||||
float max_offset;
|
||||
|
||||
DrawBeamCmd(const glm::vec3& start, const glm::vec3& end, uint32_t color, float radius,
|
||||
size_t num_segments, float max_offset)
|
||||
DrawBeamCmd(const glm::vec3& start, const glm::vec3& end, uint32_t color, float radius, size_t num_segments,
|
||||
float max_offset)
|
||||
: start(start), end(end), color(color), radius(radius), num_segments(num_segments), max_offset(max_offset)
|
||||
{
|
||||
}
|
||||
@ -49,11 +63,18 @@ struct DrawHudCmd
|
||||
struct DrawList
|
||||
{
|
||||
std::vector<DrawSurfaceCmd> surfaces;
|
||||
std::vector<DrawLightCmd> lights;
|
||||
std::vector<DrawBeamCmd> beams;
|
||||
std::vector<DrawHudCmd> huds;
|
||||
|
||||
void AddSurface(const DrawSurfaceCmd& cmd) { surfaces.emplace_back(cmd); }
|
||||
|
||||
void AddLight(const DrawLightCmd& cmd) { lights.emplace_back(cmd); }
|
||||
void AddLight(const glm::vec3& position, const glm::vec3& color, float radius)
|
||||
{
|
||||
lights.emplace_back(position, color, radius);
|
||||
}
|
||||
|
||||
void AddBeam(const DrawBeamCmd& cmd) { beams.emplace_back(cmd); }
|
||||
void AddBeam(const glm::vec3& start, const glm::vec3& end, uint32_t color = 0xFFFFFFFF, float radius = 0.1f,
|
||||
size_t num_segments = 1, float max_offset = 0.0f)
|
||||
@ -66,6 +87,7 @@ struct DrawList
|
||||
void Clear()
|
||||
{
|
||||
surfaces.clear();
|
||||
lights.clear();
|
||||
beams.clear();
|
||||
huds.clear();
|
||||
}
|
||||
|
||||
26
src/gfx/light_cache.hpp
Normal file
26
src/gfx/light_cache.hpp
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <glm/glm.hpp>
|
||||
#include "shader_defs.hpp"
|
||||
|
||||
namespace gfx
|
||||
{
|
||||
|
||||
template <size_t Size>
|
||||
struct LightArray
|
||||
{
|
||||
size_t num_lights = 0;
|
||||
glm::vec3 positions[Size];
|
||||
glm::vec4 colors_rs[Size];
|
||||
};
|
||||
|
||||
struct LightCache : public LightArray<SD_MAX_LIGHTS>
|
||||
{
|
||||
glm::vec3 center = glm::vec3(0.0f);
|
||||
size_t frame = 0;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
@ -23,11 +23,14 @@ gfx::Renderer::Renderer()
|
||||
|
||||
void gfx::Renderer::DrawList(gfx::DrawList& list, const DrawListParams& params)
|
||||
{
|
||||
++frame_;
|
||||
|
||||
current_shader_ = nullptr;
|
||||
glViewport(0, 0, params.screen_width, params.screen_height);
|
||||
glClearColor(params.env.clear_color.r, params.env.clear_color.g, params.env.clear_color.b, 1.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
CreateLightGrid(list.lights);
|
||||
DrawSurfaceList(list.surfaces, params);
|
||||
DrawBeamList(list.beams, params);
|
||||
DrawHudList(list.huds, params);
|
||||
@ -141,7 +144,47 @@ void gfx::Renderer::SetupSurfaceShader(SurfaceShader& sshader, const DrawListPar
|
||||
void gfx::Renderer::InvalidateSurfaceShader(SurfaceShader& sshader)
|
||||
{
|
||||
sshader.global_setup = false;
|
||||
sshader.color = glm::vec4(-1.0f); // invalidate color
|
||||
sshader.color = nullptr;
|
||||
}
|
||||
|
||||
static glm::u32vec3 GetLightCellCoords(const glm::vec3& pos)
|
||||
{
|
||||
// grid cell size = 20m
|
||||
// grid size = 1000x1000x1000
|
||||
return glm::clamp(glm::u32vec3(glm::floor(pos * 0.05f) + 500.0f), 0U, 1000U);
|
||||
}
|
||||
|
||||
static uint32_t HashLightGridPosition(const glm::u32vec3& coords)
|
||||
{
|
||||
return (coords.x << 20) | (coords.y << 10); // | coords.z;
|
||||
}
|
||||
|
||||
void gfx::Renderer::CreateLightGrid(std::span<DrawLightCmd> lights)
|
||||
{
|
||||
light_grid_.clear();
|
||||
|
||||
for (const auto& light : lights)
|
||||
{
|
||||
auto coords = GetLightCellCoords(light.position);
|
||||
|
||||
for (uint32_t x = coords.x - 1; x <= coords.x + 1; ++x)
|
||||
{
|
||||
for (uint32_t y = coords.y - 1; y <= coords.y + 1; ++y)
|
||||
{
|
||||
auto hash = HashLightGridPosition(glm::u32vec3(x, y, 0));
|
||||
auto& cell = light_grid_[hash];
|
||||
|
||||
if (cell.num_lights >= LIGHT_GRID_CELL_LIGHTS)
|
||||
continue;
|
||||
|
||||
cell.positions[cell.num_lights] = light.position;
|
||||
cell.colors_rs[cell.num_lights] = glm::vec4(light.color, light.radius);
|
||||
|
||||
++cell.num_lights;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawListParams& params)
|
||||
@ -170,6 +213,8 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
||||
cmd.rflags |= SRF_OBJECT_COLOR;
|
||||
else if (cmd.surface->sflags & SF_OBJECT_COLOR)
|
||||
cmd.rflags |= SRF_OBJECT_COLOR | SRF_OBJECT_COLOR_BACKGROUND;
|
||||
else if (cmd.surface->sflags & SF_MULTICOLOR)
|
||||
cmd.rflags |= SRF_MULTICOLOR;
|
||||
}
|
||||
|
||||
if (cmd.surface->sflags & SF_2SIDED)
|
||||
@ -224,6 +269,7 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
||||
const gfx::VertexArray* last_vao = nullptr;
|
||||
const gfx::UniformBuffer<glm::mat4>* last_skin = nullptr;
|
||||
const DeformTexture* last_deform = nullptr;
|
||||
size_t last_numlights = -1;
|
||||
|
||||
InvalidateShaders();
|
||||
|
||||
@ -245,17 +291,6 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
||||
for (const DrawSurfaceCmd& cmd : list)
|
||||
{
|
||||
const Surface* surface = cmd.surface;
|
||||
|
||||
// // mesh flags
|
||||
// const bool skeletal_flag = surface->mflags & MF_SKELETAL;
|
||||
// // surface flags
|
||||
//const bool twosided_flag = cmd.rflags & SRF_2SIDED;
|
||||
// const bool blend_flag = surface->sflags & SF_BLEND;
|
||||
// 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 unlit_flag = surface->sflags & SF_UNLIT;
|
||||
|
||||
SurfaceRenderFlags rflags_diff = last_rflags ^ cmd.rflags;
|
||||
|
||||
// sync 2sided
|
||||
@ -279,24 +314,32 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
||||
|
||||
auto shader = sshader->shader.get();
|
||||
|
||||
static const glm::mat4 identity(1.0f);
|
||||
const glm::mat4* model = &identity;
|
||||
|
||||
// set model matrix
|
||||
if (cmd.matrices)
|
||||
{
|
||||
glUniformMatrix4fv(shader->U(SU_MODEL), 1, GL_FALSE, &cmd.matrices[0][0][0]);
|
||||
}
|
||||
else
|
||||
{ // use identity if no matrix provided
|
||||
static const glm::mat4 identity(1.0f);
|
||||
glUniformMatrix4fv(shader->U(SU_MODEL), 1, GL_FALSE, &identity[0][0]);
|
||||
model = &cmd.matrices[0];
|
||||
}
|
||||
|
||||
glUniformMatrix4fv(shader->U(SU_MODEL), 1, GL_FALSE, &(*model)[0][0]);
|
||||
|
||||
// sync color
|
||||
if (sshader->iflags & SIF_OBJECT_COLOR)
|
||||
{
|
||||
if (sshader->color != *cmd.color)
|
||||
if (sshader->color != cmd.color)
|
||||
{
|
||||
glUniform4fv(shader->U(SU_COLOR), 1, &(*cmd.color)[0]);
|
||||
sshader->color = *cmd.color;
|
||||
sshader->color = cmd.color;
|
||||
}
|
||||
}
|
||||
else if (sshader->iflags & SIF_MULTICOLOR_DATA)
|
||||
{
|
||||
if (sshader->color != cmd.color && cmd.num_colors > 0)
|
||||
{
|
||||
glUniform4fv(shader->U(SU_COLOR), cmd.num_colors, &(*cmd.color)[0]);
|
||||
sshader->color = cmd.color;
|
||||
}
|
||||
}
|
||||
|
||||
@ -324,6 +367,37 @@ void gfx::Renderer::DrawSurfaceList(std::span<DrawSurfaceCmd> list, const DrawLi
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
}
|
||||
|
||||
// sync lights
|
||||
if ((cmd.rflags & SRF_LIT))
|
||||
{
|
||||
auto center = glm::vec3((*model)[3]);
|
||||
auto it = light_grid_.find(HashLightGridPosition(GetLightCellCoords(center)));
|
||||
|
||||
size_t numlights = 0;
|
||||
|
||||
if (it != light_grid_.end())
|
||||
{
|
||||
numlights = it->second.num_lights;
|
||||
}
|
||||
|
||||
if (numlights == 0)
|
||||
{
|
||||
if (last_numlights > 0)
|
||||
{
|
||||
glUniform1i(shader->U(SU_NUMLIGHTS), 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
auto& lights = it->second;
|
||||
glUniform1i(shader->U(SU_NUMLIGHTS), numlights);
|
||||
glUniform3fv(shader->U(SU_LIGHT_POSITIONS), numlights, &lights.positions[0][0]);
|
||||
glUniform4fv(shader->U(SU_LIGHT_COLORS_RS), numlights, &lights.colors_rs[0][0]);
|
||||
}
|
||||
|
||||
last_numlights = numlights;
|
||||
}
|
||||
|
||||
// bind texture
|
||||
if ((sshader->iflags & SIF_COLOR_TEXTURE) && last_texture != surface->texture.get())
|
||||
{
|
||||
@ -517,3 +591,4 @@ void gfx::Renderer::DrawHudList(std::span<DrawHudCmd> queue, const DrawListParam
|
||||
glDrawElements(GL_TRIANGLES, static_cast<GLsizei>(count), GL_UNSIGNED_INT, (void*)(first * sizeof(GLuint)));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -35,7 +35,7 @@ struct SurfaceShader
|
||||
|
||||
// cached state to avoid redundant uniform updates which are expensive especially on WebGL
|
||||
bool global_setup = false;
|
||||
glm::vec4 color = glm::vec4(-1.0f); // invalid to force initial setup
|
||||
const glm::vec4* color = nullptr;
|
||||
};
|
||||
|
||||
class Renderer
|
||||
@ -53,6 +53,8 @@ private:
|
||||
void SetupSurfaceShader(SurfaceShader& sshader, const DrawListParams& params);
|
||||
void InvalidateSurfaceShader(SurfaceShader& sshader);
|
||||
|
||||
void CreateLightGrid(std::span<DrawLightCmd> lights);
|
||||
|
||||
void DrawSurfaceList(std::span<DrawSurfaceCmd> queue, const DrawListParams& params);
|
||||
void DrawBeamList(std::span<DrawBeamCmd> queue, const DrawListParams& params);
|
||||
void DrawHudList(std::span<DrawHudCmd> queue, const DrawListParams& params);
|
||||
@ -68,6 +70,11 @@ private:
|
||||
std::unique_ptr<Shader> hud_shader_;
|
||||
|
||||
const Shader* current_shader_ = nullptr;
|
||||
|
||||
constexpr static size_t LIGHT_GRID_CELL_LIGHTS = SD_MAX_LIGHTS;
|
||||
std::map<uint32_t, LightArray<LIGHT_GRID_CELL_LIGHTS>> light_grid_;
|
||||
|
||||
size_t frame_ = 0;
|
||||
};
|
||||
|
||||
} // namespace gfx
|
||||
@ -17,6 +17,9 @@ static const char* const s_uni_names[] = {
|
||||
"u_sun_color", // SU_SUN_COLOR
|
||||
"u_sun_direction", // SU_SUN_DIRECTION
|
||||
"u_fog", // SU_FOG
|
||||
"u_num_lights",
|
||||
"u_light_positions",
|
||||
"u_light_colors_rs",
|
||||
};
|
||||
|
||||
// Vytvori shader z daneho zdroje
|
||||
|
||||
@ -22,6 +22,9 @@ namespace gfx
|
||||
SU_SUN_COLOR,
|
||||
SU_SUN_DIRECTION,
|
||||
SU_FOG,
|
||||
SU_NUMLIGHTS,
|
||||
SU_LIGHT_POSITIONS,
|
||||
SU_LIGHT_COLORS_RS,
|
||||
|
||||
SU_COUNT
|
||||
};
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
#define SHADER_DEFS \
|
||||
"#define MAX_LIGHTS " STRINGIFY(SD_MAX_LIGHTS) "\n" \
|
||||
"#define MAX_BONES " STRINGIFY(SD_MAX_BONES) "\n" \
|
||||
"#define MAX_COLORS " STRINGIFY(SD_MAX_COLORS) "\n" \
|
||||
"\n"
|
||||
|
||||
#define SHADER_HEADER \
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#define SD_MAX_LIGHTS 4
|
||||
#define SD_MAX_LIGHTS 8
|
||||
#define SD_MAX_BONES 128
|
||||
#define SD_MAX_COLORS 8
|
||||
@ -28,6 +28,7 @@ enum SurfaceFlag : SurfaceFlags
|
||||
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
|
||||
SF_MULTICOLOR = 0x80, // multiple color slots encoded in alpha
|
||||
};
|
||||
|
||||
struct Surface
|
||||
|
||||
@ -17,15 +17,16 @@ enum SurfaceRenderFlag : SurfaceRenderFlags
|
||||
SRF_CULL_ALPHA = 4,
|
||||
SRF_OBJECT_COLOR = 8,
|
||||
SRF_OBJECT_COLOR_BACKGROUND = 16,
|
||||
SRF_LIT = 32,
|
||||
SRF_DEFORM = 64,
|
||||
SRF_SKELETAL = 128,
|
||||
SRF_TEXTURE = 256,
|
||||
SRF_MULTICOLOR = 32,
|
||||
SRF_LIT = 64,
|
||||
SRF_DEFORM = 128,
|
||||
SRF_SKELETAL = 256,
|
||||
SRF_TEXTURE = 512,
|
||||
|
||||
SRF__SHADER = SRF_CULL_ALPHA | SRF_OBJECT_COLOR | SRF_OBJECT_COLOR_BACKGROUND | SRF_LIT | SRF_SKELETAL | SRF_DEFORM | SRF_TEXTURE,
|
||||
SRF__SHADER = SRF_CULL_ALPHA | SRF_OBJECT_COLOR | SRF_OBJECT_COLOR_BACKGROUND | SRF_MULTICOLOR | SRF_LIT | SRF_SKELETAL | SRF_DEFORM | SRF_TEXTURE,
|
||||
|
||||
// order affects visual result
|
||||
SRF_BLEND = 512,
|
||||
SRF_BLEND = 1024,
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -76,6 +76,26 @@ std::unique_ptr<gfx::Shader> gfx::CreateSurfaceShader(SurfaceRenderFlags flags,
|
||||
|
||||
input_flags |= SIF_OBJECT_COLOR;
|
||||
}
|
||||
else if (flags & SRF_MULTICOLOR)
|
||||
{
|
||||
frag_uniforms += "uniform vec4 u_color[MAX_COLORS];\n";
|
||||
frag_main += R"GLSL(
|
||||
int color_slot = clamp(int(o_color.a * 9.0), 0, MAX_COLORS);
|
||||
o_color.a = 1.0;
|
||||
|
||||
float emis = 0.0;
|
||||
|
||||
if (color_slot < MAX_COLORS)
|
||||
{
|
||||
vec4 color = u_color[color_slot];
|
||||
o_color.rgb *= color.rgb;
|
||||
emis = color.a;
|
||||
}
|
||||
|
||||
)GLSL";
|
||||
|
||||
input_flags |= SIF_MULTICOLOR_DATA;
|
||||
}
|
||||
|
||||
// alpha culling
|
||||
if (flags & SRF_CULL_ALPHA)
|
||||
@ -119,8 +139,8 @@ std::unique_ptr<gfx::Shader> gfx::CreateSurfaceShader(SurfaceRenderFlags flags,
|
||||
if (dist2 < light_radius * light_radius) {
|
||||
float dist = sqrt(dist2);
|
||||
float attenuation = 1.0 - (dist / light_radius);
|
||||
float dot_term = max(dot(sector_normal, normalize(to_light)), 0.0);
|
||||
color += light_color * dot_term * attenuation;
|
||||
//float dot_term = max(dot(sector_normal, normalize(to_light)), 0.0);
|
||||
color += light_color * attenuation;
|
||||
}
|
||||
}
|
||||
|
||||
@ -179,7 +199,16 @@ std::unique_ptr<gfx::Shader> gfx::CreateSurfaceShader(SurfaceRenderFlags flags,
|
||||
input_flags |= SIF_DEFORM_DATA;
|
||||
}
|
||||
|
||||
frag_main += "o_color.rgb *= v_color;";
|
||||
if (flags & SRF_MULTICOLOR)
|
||||
{
|
||||
frag_main += "o_color.rgb *= mix(v_color, vec3(1.5), emis);";
|
||||
}
|
||||
else
|
||||
{
|
||||
frag_main += "o_color.rgb *= v_color;";
|
||||
}
|
||||
|
||||
|
||||
vert_main = vert_pos_calc + vert_main;
|
||||
|
||||
std::string vertex_src = SHADER_HEADER + vert_attributes + vert_uniforms + vert_outs + vert_funcs + "\nvoid main() {\n" + vert_main + "\n}\n";
|
||||
|
||||
@ -17,7 +17,7 @@ enum SurfaceShaderInputFlag : SurfaceShaderInputFlags
|
||||
SIF_LIGHTING_DATA = 4,
|
||||
SIF_SKELETAL_DATA = 8,
|
||||
SIF_DEFORM_DATA = 16,
|
||||
|
||||
SIF_MULTICOLOR_DATA = 32,
|
||||
};
|
||||
|
||||
std::unique_ptr<Shader> CreateSurfaceShader(SurfaceRenderFlags flags, SurfaceShaderInputFlags& input_flags);
|
||||
|
||||
@ -78,7 +78,7 @@ std::shared_ptr<gfx::Texture> gfx::Texture::LoadFromFile(const std::string& file
|
||||
|
||||
std::shared_ptr<Texture> texture;
|
||||
try {
|
||||
texture = std::make_shared<Texture>(width, height, data, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, false, true);
|
||||
texture = std::make_shared<Texture>(width, height, data, GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, false, false);
|
||||
}
|
||||
catch (const std::exception& e) {
|
||||
stbi_image_free(data);
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user